blockchain implementation
CHAPTER 7 Building Your First Ethereum Apps 109
Chapter 7 Building Your First Ethereum Apps
The best way to learn how to write apps for the Ethereum blockchain is to start writing them. You can read about all the components and language syntax, but until you write some code, it won’t sink in. You’ve already gone through the steps to set up your development environment, so why not start using it?
Don’t worry about writing code before you know what you’re doing — you start with small, simple Solidity apps. And you learn about syntax and process as you need it. The typos you enter and other issues you encounter will help you learn faster.
The code you’ll write in this chapter is really simple. That’s okay. You’re going to learn how to write code in Solidity, and you’re going to start from the very beginning. Whether you’re new to programming or you already know several other programming languages, the exercises in this chapter will ensure that you have a working development environment and know how to write basic Solidity code.
IN THIS CHAPTER
» Exploring your development environment
» Coding in Solidity
» Writing smart contracts
» Using blockchain data
110 PART 3 Building Ethereum Distributed Blockchain Apps
Validating Your Ethereum Development Environment
When you installed the development environment components in Chapter 5, you installed each piece to operate separately. The Geth Ethereum client connects to the live Ethereum network by default. However, we don’t want to use the live Ethereum network for app development and testing. For now, you won’t need to launch Geth. You’ll use Ganache to provide the blockchain for development and testing. You looked at the settings page when you installed Ganache to view your blockchain’s host name, port number, and network ID. But you didn’t do anything with that information — until now.
Truffle is the framework you’ll use to develop and test your Solidity code. Before you can start writing code, you need to configure Truffle to use the Ganache blockchain. You do that by editing the Truffle configuration file.
Creating a Truffle project Truffle organizes software activities into projects, and stores project files in directories. If you did not create a project in Chapter 5, follow the instructions in the section on installing and downloading Truffle. (If you’d rather download the project files, go to www.dummies.com/go/ethereumfd.) After initializing the new project, type dir to see a list of files and directories Truffle created. Figure 7-1 shows a newly initiated Truffle project.
Depending on the version of Truffle you’re running, you may have two files in the project directory: truffle.js and truffle-config.js. If you open these two files, you’ll see that their contents are the same. You should always use the configuration file named truffle-config.js. To keep things simple, if your version of Truffle created the file truffle.js, just delete it.
You’ll be editing the file named truffle-config.js to configure Truffle to use the Ganache blockchain.
Because Truffle runs in Windows, macOS, and Linux, it has to handle subtle dif- ferences between the environments. The Windows operating system looks at a file with the js extension as an executable file. That means when you type the truffle command, Windows will find the local truffle.js file and try to execute it. That’s why Truffle started including the truffle-config.js file as its default configuration file. Older versions of Truffle still use truffle.js as a default configuration file- name, but I recommend that you not use it. Always use truffle-config.js or your own custom filename to avoid conflicts when you try to run Truffle in Windows.
CHAPTER 7 Building Your First Ethereum Apps 111
Editing the Truffle config file You have to edit the Truffle config file to tell Truffle to use the Ganache block- chain. Follow these steps to hook up Truffle and Ganache:
1. Get the blockchain address from the Ganache settings window. Launch Ganache, and then click or tap the Settings (gear) icon in the upper- right corner of the Ganache window. Note the hostname, port number, and network ID values. Figure 7-2 shows the Ganache settings window with default values. (You can get the host name and port number also from the main window.) The RPC SERVER value shows the host name and port number separated by a colon.
2. Launch Visual Studio Code (VS Code) for your project. Open a Windows Command prompt or PowerShell (my favorite) and navigate to your project directory (myProject.) From here, type the following and then press Enter:
code .
The code command launches VS Code, and the period tells VS Code to use the current directory as the current project. Figure 7-3 shows what your VS Code window will look like when you launch it in your myProject directory.
FIGURE 7-1: Initiating a Truffle
project.
112 PART 3 Building Ethereum Distributed Blockchain Apps
3. Modify your Truffle project configuration file to reference the Ganache blockchain.
Click or tap truffle-config.js on the left side of your VS Code window to open the file. Add the sections shown in Figure 7-4. Then save the file (choose File ➪ Save or press Ctrl+S).
FIGURE 7-2: Ganache Settings
window.
FIGURE 7-3: Visual Studio
Code in myProject.
CHAPTER 7 Building Your First Ethereum Apps 113
When you finish editing the truffle.js file, the uncommented lines (lines that don’t start with /*, *, or */) should look like this:
module.exports = { networks: { development: { host: "127.0.0.1", port: 7545, network_id: "*" // Match any network id } } };
Exploring the Ganache Test Environment Before you write any code in Solidity, you should take a look around Ganache. You’ll be coming back to this component in your development environment from time to time, so it makes sense to take a few minutes to survey what Ganache offers. Remember that Ganache is your test blockchain. You’ll need to simulate real blockchain interactions as you develop and test your code, and Ganache provides you with an environment that looks real.
FIGURE 7-4: Modified
Truffle project configuration file.
114 PART 3 Building Ethereum Distributed Blockchain Apps
When you launch Ganache, the first thing you’ll see is a list of accounts. By default, Ganache creates 10 accounts for you, each with a balance of 100 ETH. You can change this behavior in the Settings ➪ Accounts & Keys window. Every Ethereum account has a unique address, and every smart contract and transaction on the blockchain has an address that associates it with an account. So, to interact with the blockchain, you need an account address (or maybe several). You’ll use the Ganache-generated accounts to test your code throughout development. Because your accounts have a balance of ETH, they can pay fees and even transfer crypto- currency just like real blockchain accounts.
After your code starts carrying out real actions and creating transactions, you’ll be able to see those results in Ganache as well. The Blocks tab shows all blocks on your test blockchain, and the Transactions tab lists all transactions in each block. You haven’t created any blocks (other than the genesis block) or transactions yet, so there isn’t any substantive data to see right now.
The most important screen for now in Ganache is the Accounts tab, which lists the accounts you’ll use as you interact with the blockchain, as shown in Figure 7-5. You’ll see these accounts again in this chapter.
FIGURE 7-5: Ganache
accounts list.
CHAPTER 7 Building Your First Ethereum Apps 115
Designing Simple Smart Contracts Designing smart contracts is different than many other types of software development. You have to consider many blockchain nuances during all aspects of software design and development. For example, any time you access the blockchain or carry out operations, you have to pay a fee. You’ll learn about paying for blockchain access later in this chapter, but for now just be aware that a cost is associated with storage and work, so storing too much data or doing too much work could cost a lot.
Another thing to consider is that after you deploy code to the blockchain, that code can’t be changed. If you need to fix a bug or add functionality, you have to tell everyone to ignore the old code and use new code. (Well, you do if your new code works on old data. If not, you’ll have to figure out how to bind code version to data version.) Plus, the entire process of getting your code from your editor out to the blockchain is a little different than in most development workflows.
Those are just some of the issues you’ll need to keep in mind as you design and develop blockchain apps. For now, I keep things simple. The steps probably seem confusing if you’re new to blockchain development, so I won’t throw too much at you at once.
Your first smart contract is the familiar Hello World program. If you’ve ever writ- ten software in any language, chances are you wrote a simple program that dis- played the message Hello World. The Hello World program is a tradition that has been around since the early days of computing. Writing this simple program will give you the concrete steps you have to follow for all your development activities.
You’ll write a smart contract that displays the message Hello World. You might be surprised at the number of steps to display that simple message, but as your apps become more complex, you’ll essentially follow the same process.
As you design your own smart contacts, consider what each one must do. Smart contracts are objects, so you can think about them as a combinations of data and functionality. Each smart contract can store some data and will always have actions it can perform. You can think of data as nouns and actions as verbs. Your HelloWorld smart contact has one data item, helloMessage, and can do one thing, getHelloMessage(). In Solidity, simple data items are variables and actions are functions.
That’s all that your HelloWorld smart contract needs to do, so you’re ready to start coding.
116 PART 3 Building Ethereum Distributed Blockchain Apps
Coding Your First Smart Contract Your HelloWorld smart contract has only five lines of code. To get started writing your first smart contract, right-click the Contracts folder in VS Code Explorer, and then click New File to create a new file in the Contracts folder.
Type HelloWorld.sol in the filename text box and press Enter. VS Code opens your new file in a new Editor tab. Type the following text in the VS Code editor:
pragma solidity ^0.4.24;
contract HelloWorld {
string private helloMessage = "Hello world";
function getHelloMessage() public view returns (string) {
return helloMessage;
}
}
The semicolons and curly braces may appear to be in random places, but they each have a purpose. Don’t worry too much about punctuation right now. Just type the code as shown.
Let’s look at each line of code. The first line is
pragma solidity ^0.4.24;
The first line of every smart contract is (or should be) the version pragma. It tells Solidity what version of the compiler is expected to be used to compile this smart contract. Solidity is still a new language, and it changes a little with each version. In fact, major version updates of the compiler often will not compile all Solidity written using earlier versions. The version pragma helps to avoid compilation failures just because you’re using a newer Solidity compiler.
To use the version pragma, you provide the lowest version of the compiler that should compile this code. In the example, I provided the specific Solidity version, 0.4.24. I could have used 0.4.0, which means “the latest minor version within the 0.4 major version.” Also note that I added the caret (^) to the beginning of the version. The caret tells Solidity to allow only minor versions of the compiler in the 0.4 major version range. In other words, don’t use a 0.5.0 compiler.
If you want to see the version of the Solidity compiler that Truffle is using, open a terminal (in VS Code, click or tap Terminal ➪ New Terminal from the top menu bar). Type the command truffle version. You’ll see the Truffle and Solidity compiler versions.
CHAPTER 7 Building Your First Ethereum Apps 117
The next line of code defines the smart contract:
contract HelloWorld {
At this point, all you need to provide is the keyword contract and the contract’s name, HelloWorld.
After defining the smart contract and giving it a name, you define a data item:
string private helloMessage = "Hello world";
You want to store a string in memory, so you define a Solidity variable. You define the helloMessage variable as a string datatype. You’ll learn about more datatypes in Chapter 8; for now, we’ll use string. Before finishing this line of code, you store the value "Hello world" in the helloMessage variable. You need to use this variable only in the helloMessage function, so you tell Solidity that it is a private variable.
In the next line, you define the only action, or function, in your smart contract:
function getHelloMessage() public view returns (string) {
The function keyword tells Solidity that you’re going to write some code that you’ll execute by calling the function’s name, getHelloMessage(). To declare a function, you provide the function keyword, the function name, who can see it and use it, the mutability modifier, and what type of data it returns to the caller. Your function is named getHelloMessage. You want anyone to be able to call it, so you tell Solidity that it is a public function. The view modifier tells Solidity that this function will be allowed to only read and return state variables. It cannot modify the blockchain. And finally, your function will return, or send back, a string to whatever calls it (returns).
The last line of code does all the real work:
return helloMessage;
This line of code tells the function to return control to the caller and pass the contents of the helloMessage variable back in the process. The two lines follow- ing the return statement are just closing curly braces to tell Solidity that the function and contract have ended. The closing braces are like closing parentheses when you write. They finish up whatever you’re wrapping in curly braces.
You can save the file at any time by clicking or tapping File ➪ Save on the top menu bar, or by pressing Ctrl+S. Go ahead and save your first smart contract.
118 PART 3 Building Ethereum Distributed Blockchain Apps
Running Your First Smart Contract The only thing left is to make your smart contract display Hello World. To do that, you have to run your smart contract. Here are the high-level steps for running code in the Ethereum environment:
1. Write the smart contract source code. Write the smart contract and any supporting code.
2. Compile the smart contract. This step creates the bytecode that the EVM executes.
3. Deploy the compiled smart contract to the Ethereum blockchain. This step writes your smart contract code to a block on the blockchain.
4. Call (invoke) a function in the smart contract. This step finds your smart contract code and carries out the actions you request.
Writing your code You’ve already written the source code for your HelloWorld smart contract, but that isn’t all you need to do. You also need a way get your code onto the block- chain. That process is called deploying code (as noted in Step 3 in the preceding steps). The deploy step runs deployment, or migration, code.
You should go ahead and write it now while you’re still in code editing mode:
1. In VS Code, right-click the Migrations folder in Explorer, and then click New File to create a new file in the Migrations folder.
2. Type 2_contracts_migration.js in the filename text box and press Enter. VS Code opens your new file in a new Editor tab.
3. Type the following text in the VS Code editor: var HelloWorld = artifacts.require("HelloWorld"); module.exports = function(deployer) { deployer.deploy(HelloWorld);
};
CHAPTER 7 Building Your First Ethereum Apps 119
We won’t go into many details of this JavaScript code. This file finds the Hello- World compiled bytecode and calls a deploy function to place the code in a block on the blockchain. You learn more about deploying smart contracts when you write more complex smart contracts. For now, just enter the preceding code to set up your project to deploy your new smart contract.
Compiling your code You can compile your smart contract code at any time in VS Code by pressing the F5 key. When the compile starts, VS Code opens a new view at the bottom of your window with four tabs: Problems, Output, Debug Console, and Terminal. I hope the compile completes without errors. If you do see errors, go back and make sure that your code looks exactly like the example HelloWorld smart contract in the preceding section.
Sometimes you’ll get errors because of a mismatch between compiler versions. The safest option when learning Solidity is to ensure that your VS Code extension and Truffle use the same Solidity compiler version. You already know how to find the Truffle compiler version (type truffle version at a PowerShell prompt). Click or tap the Output tab in the new view that opened when you started the compile. It should display the compiler version it uses for compiling code in VS Code. If the version doesn’t match your Truffle Solidity version, you should change it in VS Code to match the Solidity version that Truffle uses.
If you need to change the Solidity compiler version that VS Code uses, you can do that from within VS Code:
1. Find the version of the compiler you need by launching your browser and navigate to https://github.com/ethereum/solc-bin/tree/gh-pages/bin.
This page lists all Solidity releases.
2. Scroll down until you find a file named soljson-v followed by the version of the compiler that you want.
In the case of HelloWorld, the version is 0.4.24. You’ll see a list of files for each version.
3. Find the file that has +commit after the version. Click or tap the descrip- tion next to the filename.
4. In the next window, copy the complete compiler version. The version will start with v0. For the HelloWorld smart contract, the version is v0.4.24+commit.e67f0147.
120 PART 3 Building Ethereum Distributed Blockchain Apps
5. Back in VS Code, click or tap the .vscode folder in Explorer view, and then click or tap settings.json to open the file in the VS Code editor.
6. Click or tap User Settings in the upper-right window, and scroll down in the middle window until you see Solidity Configuration.
7. Click or tap Solidity Configuration and then click or tap solidity. compileUsingRemoteVersion.
8. Type the following three lines in the upper right window (right under the Place your settings here to overwrite the Default Settings message):
{
"solidity.compileUsingRemoteVersion": "v0.4.24+commit.e67f0147" }
Replace v0.4.24+commit.e67f0147 with the compiler version that you copied in Step 4 above.
9. Save the file and close it (by clicking or tapping the X on the tab for this file).
Now your VS Code compiler should match the version Truffle uses.
After your smart contract compiles in VS Code, you can proceed to the next step.
Deploying your code After you have finished writing your smart contract code, it’s time to test it and eventually place it into production. As mentioned, the process of copying smart contracts to the blockchain is called deployment. When you deploy smart contracts, you copy the code into a new block. The new smart contract gets an address and can be run on the EVM.
Because you’re using the Truffle framework, the process to deploy your smart contracts is simple. Open the Terminal window (click or tap Terminal in the menu bar), and type the following:
truffle deploy --reset
Make sure that Ganache is running before you type the deploy command. If you use Microsoft Windows and Ganache isn’t running, click or tap the Windows button and then type Ganache. The Windows Search function should find Ganache and highlight its shortcut. Click or tap the Ganache shortcut to launch the Ganache program. Because the purpose of building dApps is to send smart contracts to the blockchain, a blockchain has to be available.
CHAPTER 7 Building Your First Ethereum Apps 121
Truffle compiles your smart contracts and then uses the JavaScript files in the Migrations folder of your project to migrate, or deploy, your smart contracts to the blockchain. Figure 7-6 shows the output of the deploy command. Note that Truffle places each smart contract into a block and returns the address of the smart contract. You’ll use this address to find the smart contract again and invoke its functions.
This is the first time you’ve interacted with the blockchain. The deployment process created a new block and placed your smart contract code into it. To see this activity, click or tap the Blocks tab in Ganache to see the blocks on your blockchain.
Each action in the deployment process created a new block with a single transac- tion. At least four blocks should be on the blockchain now. Figure 7-7 shows the blocks view in Ganache.
You can see the bytecode for smart contracts, too. Click or tap the Transactions tab to list the transactions in your blockchain. Click or tap a Contract Creation button to view the contents of a smart contract. Figure 7-8 shows the contents of a smart contract in the Ethereum blockchain. TX Data contains the bytecode for the smart contract.
FIGURE 7-6: Truffle
deployment results.
122 PART 3 Building Ethereum Distributed Blockchain Apps
Invoking your code’s functions The final step in running smart contract code is to invoke one or more functions in your smart contract. You have only one function, getHelloMessage(), in your smart contract, so that’s the one you’ll invoke.
FIGURE 7-7: Ganache blocks after deploying
smart contracts.
FIGURE 7-8: Contents
of a smart contract block.
CHAPTER 7 Building Your First Ethereum Apps 123
Before you can invoke code in a smart contract, you have to know where it resides on the blockchain. First, let’s get some information about the smart contract, including its address from the blockchain. In your Terminal window, launch the Truffle console. Type the following command and then press Enter:
truffle console
The Truffle console allows you to interact directly with the blockchain. Type the following command at the Truffle console prompt and then press Enter:
HelloWorld.deployed().then(function(instance) {return instance });
This command goes to the blockchain and reads an instance of the HelloWorld deployed smart contract. It creates a lot of output, including the bytecode and the original source code of your smart contract.
Figure 7-9 shows the Terminal window with the results of the preceding com- mand. Note the deployedBytecode and source values.
Now that you have an instance of your smart contract (that is, a pointer to where your smart contract is running in memory), you can use it to invoke any of its functions. Type the following command at the Truffle console prompt, and then press Enter:
HelloWorld.deployed().then(function(instance) {return instance.
getHelloWorld() });
This command invokes the getHelloMessage() function in the HelloWorld smart contract and displays the results. You should see the “Hello world” message in the
FIGURE 7-9: Smart contract
instance information.
124 PART 3 Building Ethereum Distributed Blockchain Apps
Terminal window. That may seem like a lot of work just to display a message, and it is. But the process you just learned is one that you’ll use over and over to develop, test, and deploy smart contracts, regardless of how complex they may be.
Paying as You Go You may have noticed in Ganache that blocks and transactions each have a Gas Used value. The Ganache main window also shows the Gas Price and Gas Limit for the blockchain. You learn a lot more about gas in Chapter 8, but you need to know a little about transaction costs now, before you start writing bigger and more functional smart contracts.
Gas is a unit of value in Ethereum. Every operation that a smart contract carries out costs some number of gas units. For example, you have to pay 30 gas to calculate a Keccak256 hash, plus another 6 gas for every 256 bits (not bytes) of data you want to hash. The amount you pay for operations is called the gas cost.
Charging gas for computation forces smart contract developers to think about how they write code. You can write inefficient code, but it will cost you. Also, gas provides a great way to keep malicious code from taking over EVMs. Every transaction has a gas limit, and when the EVM reaches that limit, it stops the contract. Gas limits protect EVMs from many types of denial of service (DoS) attacks.
Every transaction sets a gas price, which is the highest amount of ETH that transaction is willing to pay for each gas unit. Transactions also set a gas limit, which is the maximum amount of gas the transaction is willing to pay. If the execution consumes enough gas to equal the gas limit, the EVM stops execution of the transaction. That is one reason a transaction may not succeed. Alternatively, if the gas price is set too low, a transaction may never be added to a block because miners did not want to waste their processing time on a transaction with too small of a reward. Miners generally try to mine blocks with transactions that have a high enough gas price to make the mining process profitable.
The takeaway is that creating transactions in the Ethereum blockchain requires a fee. That fee is charged in gas units and can be limited to a range with which you are comfortable. Paying more gas often means getting your transaction processed quicker, but paying too much wastes money. As you write smart contract code, pay attention to the operations that incur gas cost. As you learn more about Solidity in Chapter 8, you’ll learn ways to write code that conserves operations that require gas.
CHAPTER 8 Learning about Smart Contracts 125
Chapter 8 Learning about Smart Contracts
Smart contracts are the functional part of any blockchain solution. Just like the objects you learn about in Chapter 7, a blockchain solution is a combina-tion of data and actions on that data. The data is the content of the blocks on the blockchain. You already know that after data is added, it stays there forever. (Although you could technically change blockchain data, doing so without any other node detecting your change is next to impossible.) Because blockchain data is immutable, it is important to carefully control how that data is added.
The actions that operate on the blockchain data are the smart contracts. You already know that smart contracts, like the data, are stored in blocks on the block- chain. But smart contracts execute on all EVMs and have to work the same way and produce the same results on all EVMs. Smart contracts govern the way that data is added to the blockchain and how that data can be used.
In Chapter 7, you wrote a simple smart contract, but it didn’t do anything useful. The only way to create a smart contract to do anything useful is to identify a real- world problem and then create a blockchain solution that solves the problem. One use case that is a good fit for a blockchain solution is supply chain management.
IN THIS CHAPTER
» Describing Supply Chain and its challenges
» Exploring a blockchain solution to supply chain
» Handling data and computation in Solidity
» Coding to limit gas cost
» Controlling execution flow and responding to errors
126 PART 3 Building Ethereum Distributed Blockchain Apps
In this chapter, you learn about some supply chain challenges and how blockchain can address some of them. You also learn more about Solidity smart contracts by developing a solution to a current supply chain problem.
Introducing Supply Chain and Common Challenges
In today’s economy, nearly every product you use or service you consume comes from some other source. Although you might grow your own vegetables and herbs, you likely don’t raise livestock as a meat source as well. Everything that you buy comes from an original producer. In the case of food products, the original producer could be a grower, a rancher, a fisherman, or a producer of any other type of food.
As society has moved from being self-sufficient to relying on others to supply products services, consumers have become detached from producers. Geographic distances, regulations, and the suppliers’ desires for greater reach and higher profits have given rise to aggregators and middlemen to handle goods. These middlemen provide benefits to producers and consumers but also require fees for their services. These fees increase the consumer price, and the processing may slow down the time it takes for goods to arrive to the market or consumer.
Describing supply chain Consider what happens when you buy fish. If you live near the coast, you might go to the docks and purchase fish directly from the fishing boat. However, it is more likely that you bought the last fish you ate from a market or a restaurant. That means one or more parties were between the fishermen (the producer) and you (the consumer). The framework that connects consumers to producers, along with the system that manages it, is called a supply chain. A supply chain might have only a single participant between the producer and consumer, or it might contain many participants along the way. A supply chain manages all assets, along with han- dling the payments tendered in exchange for the products or services.
In a simple supply chain, fishermen may sell their fish directly to markets near the docks where their ships bring a fresh catch each day. Consumers shop at the markets and purchase fish from a single middleman. If you don’t live near a mar- ket like that, the fish may go to a processor, then to a shipper, then on to a ware- house, and finally to a retail store, where the consumer purchases the fish. That is an example of a common supply chain. As consumers demand more options, sup- ply chains exist to help producers provide the products and services that consum- ers demand.
CHAPTER 8 Learning about Smart Contracts 127
Supply chain participants provide value to small and large producers. For the small producers, an aggregator can collect product from multiple producers and provide larger shipments to processors or warehouses. Large producers benefit from having local points of entry into the supply chain, without having to handle point-to-point shipments to all outlets for their products.
Consumers benefit as well because the supply chain makes available a wide variety of products from many producers.
Explaining difficulties when implementing a supply chain So far, a supply chain sounds like a great way to get products and services to a wide variety of consumers. And it does do all that. But the current supply chain approach has obstacles, or limitations. In general, five types of obstacles are encountered in today’s supply chain implementations, as listed in Table 8-1.
TABLE 8-1 Supply Chain Obstacles Obstacle Description
Lack of transparency
Today’s supply chain participants often manage their own data systems and don’t publish their internal data. Separately managed data systems makes it difficult to see how items are processed at each step in the chain.
Lack of traceability
With limited transparency at each step, the data required for tracing products to their ori- gin is often not available, making authenticity claims and recall notices for points of origin difficult or impossible.
Transfer time lags
Transferring products from one participant to another requires synchronization between organizations and might not occur in real time. Many transfers occur in batches based on scheduled operations. This can cause delays at every stage, resulting in cumulative delays throughout the chain.
Translation data loss
Each participant receives, manages, and passes along its own core set of data. Even with decades-old standards, such as Electronic Data Interchange (EDI), some data items might not be passed along from one participant to another, resulting in granular data loss along the supply chain. Also, any data that must be re-keyed because it isn’t passed along is sub- ject to human error.
Nonstandard/ unavailable sta- tus tracking
Because each participant generally manages its own data, status updates might not be available at each stage. Some participants might either decline to provide status updates or provide them in a manner that is incompatible with status updates from other partici- pants. In the latter case, the status update requestor is required to assimilate status updates in various formats and harmonize them into meaningful output.
128 PART 3 Building Ethereum Distributed Blockchain Apps
The items in Table 8-1 represent just some of the obstacles in supply chain imple- mentations in production today. These problems tend to be more pronounced as the complexity of a supply chain increases. But as many markets mature and become more global, supply chains nearly always become more diverse and com- plex. Pursuing solutions to these obstacles is important to global commerce.
Examining How Blockchain Can Help Resolve Supply Chain Problems
Blockchain technology can help address many of the supply chain obstacles. While no single solution is a perfect fit for any situation, blockchain, and Ethereum is particular, can help resolve the majority of the shortcomings of today’s supply chain implementations. Table 8-2 lists the obstacles from the previous section, and how Ethereum can help resolve each one.
Ethereum provides a level playing field for many uses, including supply chains. In an environment that includes participants who do not fully trust one another, or are even competitors, Ethereum makes it possible to conduct business in a fair
TABLE 8-2 Ethereum Solutions to Supply Chain Obstacles Obstacle Description
Lack of transparency
Blockchain technology does not have a central authority. All transactions are published to the shared blockchain. Any participating node can view transactions and verify their authenticity.
Lack of traceability
Because all nodes have access to all transactions on the blockchain, linking transactions is almost trivial. Any node can easily construct a complete chain of transactions between the original producer and the final consumer.
Transfer time lags
Smart contracts provide the capability to assess the current blockchain state and make decisions on demand. Legacy solutions often require human interaction, which depends on set working hours. Blockchain introduces the opportunity for smart contracts, not humans, to make certain decisions immediately. This benefit can remove the need for human intervention in some types of decisions.
Translation data loss
Ethereum smart contracts define data needed for each transaction and ensure that all participants provide the same input. In short, every node uses the same rules — the rules don’t change from participant to participant as you move along the supply chain.
Non-standard/ unavailable sta- tus tracking
Instead of each participant responding individually to status update requests, all neces- sary information is in blocks on the blockchain. Anyone who can access the blockchain can determine the current status of any digital asset.
CHAPTER 8 Learning about Smart Contracts 129
manner. Supply chain implementations can be far more comprehensive than just tracking how products move to the consumer. Participants along the supply chain can also add their own value.
For example, an elaborate supply chain can operate like a distributed manufactur- ing or assembly line. High-end corporate aircraft often undergo customizations after the aircraft leaves the manufacturer but before delivery to the customer. For example, the aircraft might go to several other companies for interior fitting, painting, and even aftermarket performance upgrades. Each step likely includes additional services and products that add to the original aircraft — for a fee.
Ethereum makes it possible to track and control products through multiple steps, and provides a secure way to provide transparency and traceability for all products to all parties.
Describing a Blockchain Supply Chain Solution
You’ve learned about what an Ethereum supply chain solution can do, but you still need to see how it will operate before you start writing code. For the rest of this book, you’ll implement a simple supply chain solution in Solidity. This solution will provide the absolute basic actions you’ll need to track and manage products and payments from initial production to the final consumer.
Your supply chain solution will consist of two smart contracts. One smart contract will handle payments and the other will handle the asset tracking and manage- ment. Because you’ll be focusing on learning about smart contracts, your solution won’t implement every imaginable supply chain function. But when you’re done, you’ll appreciate how powerful Ethereum is and, I hope, be motivated to write your own smart contracts to solve your own problems.
Paying for supply chain services Each link in a supply chain provides a service. A supply chain participant might ship goods from one place to another, store goods in a warehouse, add value to products, or even place goods on shelves at retail locations. Unless your organiza- tion is a non-profit, the main goal for participating in supply chain is to make money. That means you’ll have to pay every time a product moves from one par- ticipant to another.
130 PART 3 Building Ethereum Distributed Blockchain Apps
Although you could use traditional payment processing, you’re going to learn how to do it using Ethereum! The easiest way to send and receive funds in Ethereum is by using a token. An Ethereum token is a type of cryptocurrency for a particular dApp. You’ll be creating a supply chain token based on the popular ERC-20 Ethe- reum token standard.
Although several Ethereum token standards are available, ERC-20 is by far the most popular. You can see how many tokens exist by navigating to https:// etherscan.io and click or tapping Tokens — ERC-20 Top Tokens. At the time of this writing, there were more than 155,000 different ERC-20 tokens.
You can think of a token as a college student ID with money in a special account. To avoid carrying around cash or multiple cards, many college students pay for things on campus using their IDs. The “college cash” attached to their ID is good only on campus, but it’s convenient and makes it easy for on-campus vendors to identify students and offer special pricing.
Your token smart contract will contain all the rules to manage your balance of cryptocurrency. You’ll write the code to check your balance, transfer funds to another Ethereum address, and receive funds from another Ethereum address.
Managing assets on the supply chain The main smart contract for your supply chain will contain the core functions to manage assets. From a technical sense, Ethereum can’t manage physical assets. It can manage only digital assets. Think about tracking your bags when you fly on a commercial airline. Many airlines provide status updates via a mobile app. They tell you when your bag gets loaded on the airplane and where to pick it up when you arrive at your destination. However, the airline isn’t tracking your bag — they’re tracking the tag on your bag. The tag is a generated version of a digital asset that the airline tracks.
The difference between a physical asset and a digital asset is obvious on one hand but subtle on the other hand. Continuing the airline luggage example, problems can occur at the cyber-physical barrier. If the human or device that attaches the tag to the bag doesn’t get it right, nothing works from there on. When I recently flew from San Antonio, Texas to Atlanta, Georgie, I arrived but my bag did not. When the airline baggage representative investigated, we found that my baggage tag was attached to another traveler’s bag. Because the airline tracks and manages their tags, they sent the wrong bag (with the right tag) to Atlanta. Unfortunately, my bag (with the other traveler’s tag attached to it) went to Mexico City. It took me almost a week to get my bag back.
CHAPTER 8 Learning about Smart Contracts 131
That story should help point out how important it is to maintain the cyber-physical relationship. Physical goods have to be associated with a digital asset to be man- aged in any computing environment. In many cases, that means the entry point of the supply chain creates a tag or other method of positively identifying the physical asset. Regardless of the identification option you choose, you’ll need a number or an identifier that corresponds to a single physical asset. Table 8-3 lists a few options for associating physical assets with their digital mirror assets.
Your supply chain smart contract assumes that some external device or other entity creates a trusted digital string or number that uniquely identifies a physical asset. After you have a digital asset ID, your smart contract will define functions that will carry out these actions:
» Creating a new supply chain participant: Validates a new participant and authorizes the participant to become part of the supply chain process.
» Adding a new product to the supply chain: Puts a product into the supply chain process.
» Transferring ownership of a product to another participant: Carries out the main action of transferring a product from one supply chain participant to another.
» Tracking a product: Provides status updates of a product and its history on the supply chain.
TABLE 8-3 Connecting Physical Assets to Digital Assets ID Method Pros Cons
Engraving an identifier on each product
Unique to each item and difficult to alter
Expensive and slow
Attaching a printed label to each product
Unique to each item and useful for a wide variety of products
Labels can be damaged or lost
Attaching a printed label to a box of products
Fast for products managed in batches
Difficulty handling opened boxes with missing product
Using a manufacturer- generated identifier
Integrates with manufacturer’s data, and fast if identifier can be scanned
Potentially different formats or locations for different manufacturers, and depends on external data provider
Attaching an RFID tag Fast and easy to scan More expensive than printed labels, and tags can detach
132 PART 3 Building Ethereum Distributed Blockchain Apps
Your two smart contracts will work together every time a product transfers from one participant to another. At the moment a product’s owner changes, the partici- pants making the transfer will use the ERC-20 token to exchange funds to pay for the asset. Figure 8-1 show how your supply chain process will work.
Digging into Solidity Solidity is the language you’ll use to write smart contracts in the examples in this book. Solidity was proposed by Gavin Wood in August 2014. Although it isn’t the only language you can use to write smart contracts, it is the most popular language for writing smart contracts that run in the Ethereum. It enjoys solid support from the Ethereum community and was developed by the Ethereum project’s Solidity team.
Solidity was designed to be similar to JavaScript and was influenced by a few other popular programming languages as well, including C++ and Python. The goal of Solidity is to provide a language that is familiar to web application developers but targeted at smart contract development. Solidity isn’t intended not as a general- purpose language but to support blockchain specific operations with code that runs in the EVM.
Before your code can run in the EVM, you have to compile it. That’s why one of the components you installed when building your development environment was a Solidity compiler. You first write your Solidity source code in an editor. Then you compile it into bytecode, which are the instructions that run in the EVM. After you deploy your smart contract bytecode, it runs on all Ethereum nodes.
FIGURE 8-1: Ethereum supply
chain flow.
CHAPTER 8 Learning about Smart Contracts 133
Because smart contracts run on all nodes, Solidity must enforce determinism, that is, the results must be the same for all nodes running your smart contract code with the same input. If you look at the Solidity documentation, you won’t find a random() function. That omission is specifically to support Solidity’s determin- ism. Your code gets run first by the node that mines a new block, but then all nodes verify the block and run the code to ensure that they don’t get a different result.
In many ways, Solidity is similar to other programming languages. The biggest differences are in how the programs are run and how Solidity deals with data. You’ll learn more about Solidity data handling later in this chapter. But for now, note that Solidity deals with data only in the EVM or the blockchain.
Solidity doesn’t interact with the outside world much, but it is possible. Solidity supports the concept of an oracle, which is a trusted source of information from the outside world. Calling an oracle is easy. One problem is being able to trust the oracle. Another problem is dealing with oracle data that may return different data each time it’s called. Before using any oracles, you must ensure that the data source is trustworthy and consistent. It is common for oracles to return data and some proof of authenticity.
The concept of trust with respect to oracles is just an extension of blockchain trust. Remember that blockchain technology provides a trusted ledger of data in an envi- ronment of trustless network nodes. Because trust is such a foundational property of blockchain, it isn’t surprising that trusting an oracle is an important concern.
Describing Basic Smart Contract Syntax You’ve already seen a little Solidity syntax. Now it’s time to learn some more. When you write Solidity source code, you save that code in a file with the exten- sion .sol. You may recall from Chapter 7 that you stored your Hello World smart contract in the file HelloWorld.sol.
A Solidity program has several main sections, as follows:
» Pragma: This tells Solidity what versions of the compiler are valid to compile this file.
» Comments: Developers should use comments for documenting code. » Import: An import defines an external file that contains code that your smart
contract needs.
» Contract(s): This section is where the body of your smart contract code resides.
134 PART 3 Building Ethereum Distributed Blockchain Apps
Declaring valid compiler version The pragma directive should be the first line of code in a Solidity file. Because the Solidity language is still maturing, it is common for new compiler versions to include changes that would fail to compile older programs. The pragma directive helps avoid compiler failures due to using a newer compiler.
Here is the syntax for the pragma directive:
pragma Solidity <<version number>>;
Here is a sample pragma directive:
pragma Solidity ^0.4.24;
All statements in Solidity end with a semicolon.
The version number starts with a 0, followed by a major build number and a minor build number. For example, the version number 0.4.24 refers to major build 4 and minor build 24. The caret symbol (^) before the version number tells Solidity that it can use the latest build in a major version range. In the preceding example, Solidity can use a compiler from any build in the version 4 build range. This is a way to tell readers that your program was written for 0.4.24 but will still compile for subsequent version 4 builds.
Although using the caret in the pragma directive provides flexibility, it is a better practice to drop the caret and tell Solidity exactly what compiler version you expect.
Commenting your code Adding comments to your code is an extra step that adds a professional look and feel to your code. A well-commented source code file is easier to read and under- stand and helps other developers quickly understand what your code is supposed to do. Even simple comments can cut down on the time required to fix bugs or add new functionality. Comments can also provide input for utilities to generate doc- umentation for your smart contracts.
You can use single-line or multiline regular comments. Single-line comments start with two forward slashes. Multiline comments start with the /* characters and end with the */ characters. Here is an example of Solidity comments:
// Here is a single line Solidity comment /* I have a lot more to say with this comment, so I'll
CHAPTER 8 Learning about Smart Contracts 135
use a multiline comment. The compiler will ignore everything after the opening comment characters, until it sees the closing comment characters. */
A third type of Solidity comment is called the Ethereum Natural Specification (NatSpec) directive. You can use NatSpec to provide information about your code for documentation generators to use to create formatted documentation the describes your smart contracts. NatSpec directives start with three forward slashes and include special tags with data for the documentation. Here is an example of using NatSpec directives:
/// @title Greeter smart contract /// @author Joe Programmer /// @notice This code takes a person's name and says hello /// @param name The name of the caller /// @return greeting The greeting with the caller's name
You can find NatSpec documentation and additional information at https:// github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format.
Importing external code The import section is optional but can be powerful. If your smart contract needs to refer to code in other files, you’ll have to import those other files first. Import- ing files makes it as though you copied the other code into the current file. Using imports helps you avoid actually copying code from one place to another. If you need to access code, just import the Solidity file that contains it.
The syntax for importing other files is simple. You use the import keyword and then provide the filename for the file you want to import. For example, to import the file myToken.sol, use this syntax:
Import 'myToken.sol';
Defining your smart contracts In the last main section of Solidity, you define the contents of your smart contract. It starts with the keyword contract and contains all of the functional code in your smart contract. You can have multiple contract sections in Solidity. That means a single .sol file can define multiple contracts. Here is an example contract section (you might recognize this code from Chapter 7):
contract HelloWorld { string private helloMessage = "Hello world";
136 PART 3 Building Ethereum Distributed Blockchain Apps
function getHelloMessage() public view returns (string) { return helloMessage; } }
Inside the contract section is where you define all of your variables, structures, events, and functions. There’s a lot more to the contract section of your code, but for now, you know how to set up a Solidity smart contract. In the next section you learn more about what goes into the contract section.
Handling Data in Solidity Solidity is particular about where you can store data. You generally define two types of variables in Solidity: state variables and local variables. You define state variables in the contract section, and those variables are available anywhere in the smart contract. These variables store the state of your smart contract by saving the values in a block on the blockchain. You define local variables inside functions. Local variables don’t save their values between function calls. Those values aren’t stored on the blockchain and go away when the function ends.
Solidity defines three places for storing data:
» Stack: Where Solidity stores local simple variable values defined in functions. » Memory: An area of memory on each EVM that Solidity uses to store tempo-
rary values. Values stored here are erased between function calls.
» Storage: Where state variables defined in a smart contract reside. These state variables reside in the smart contract data section on the blockchain.
Variable storage location is one of the more confusing aspects of Solidity. I cover the basics now, and come back to some finer points in Chapter 9. The Solidity language doesn’t have a stack keyword but does have memory and storage key- words. Solidity uses its own defaults, depending on where you define variables and how you use them, but you can override some of these defaults and also use the keywords to modify how Solidity treats variables.
Here are a few rules that help keep things straight when learning about storing data in Solidity:
CHAPTER 8 Learning about Smart Contracts 137
» State variables are storage by default (values are stored in the blockchain). » Local variables in functions are memory by default (values are stored tempo-
rarily in memory).
» Structs are storage by default (values are stored in the blockchain).
Solidity can handle different types of data and provides different types of variables to handle each type. When you define variables, you have to specify the datatype of the variable. The datatype tells Solidity how much space to allocate for the value you will store in the variable and how to treat the data. Table 8-4 lists the data types that Solidity supports.
As your smart contracts become more complex, you’ll probably need to represent more complex types of data. For example, you might want to define a physical address type that contains several pieces of information, including street address, city, state, and postal code.
You also might need to store tables or lists of data. Solidity allows you to create your own data structures with the struct complex data type. You can also define arrays that store groups of similar data items. Solidity arrays can be groups of simple data types or groups of structs. You use structs and arrays in the smart contracts you write in Chapter 9.
Here is a smart contract that demonstrates some of Solidity’s simple data types. In this example, you’re using only state variables, which means you’re writing to the blockchain. Defining all of your variable as state variables is not a good idea unless you want to store data forever. Data stored to the blockchain requires expensive operations and shouldn’t be used unless you need to store your data persistently. For now, you’ll use state variables, but in Chapter 9 you learn how to define local variables as well.
Open VS Code for the myProject project:
To open VS Code in the myProject project, open a Windows Command prompt or PowerShell (my favorite) and use the cd command to navigate to your project directory (myProject.) From here, just enter the following command and press Enter:
code .
138 PART 3 Building Ethereum Distributed Blockchain Apps
Then type the following code. (If you’d rather download the project files, go to www.dummies.com/go/ethereumfd.)
pragma solidity 0.4.24;
/*
* @title Solidity data types
* @author Michael Solomon
TABLE 8-4 Solidity Data Types Data type Comments Example When to use
uint 32-byte (256 bit) unsigned inte- ger. You can also define smaller uints as uint8, unit16, . . . up to uint256 (which is the same as uint).
uint x = 10;
uint16 x = 44;
To store positive integers. Using smaller uints (such as uint8) saves storage space and processing cost.
int 32-byte (256 bit) signed integer. You can also define smaller ints as int8, int16, . . . up to int256 (which is the same as int).
int x = -10;
int32 x = 45;
To store integers with negative and positive values. Using smaller ints (such as int8) saves storage space and pro- cessing cost.
byte A single byte. You can also define arrays of 1–32 bytes using the type bytes2, byte3, . . . up to bytes32.
byte singleChar = 't';
bytes16 msgHello = 'Hello, world!';
To store any number (up to 32) bytes. The bytes datatype makes it easy to access and manipulate array contents.
string 32-byte array of characters. This datatype is most often used to store strings of UTF-8 characters.
string myString = "Hello, world!";
To store character strings. Solidity strings are difficult to manipulate directly. In most cases, using bytes is more convenient.
bool Boolean, or logical, values (yes/no or true/false).
bool isOK = true; To store yes/no, true/false values.
address 20 byte Ethereum address. address myAddress; To store an Ethereum address.
mapping A dictionary that relates key to a value. Mappings provide an easy method to lookup a value that corresponds to a key.
mapping (address => uint) balances;
To lookup data for a specific key, such as finding the bal- ance of an account.
enum Enumerated list of options. enum surveyResult { StronglyDis- agree, Disagree, Neutral, Agree, StronglyAgree };
To store meaningful values from a limited set of choices.
CHAPTER 8 Learning about Smart Contracts 139
* @notice A simply smart contract to demonstrate simple data types available in
Solidity
*
*/
contract DataTypes {
uint x = 9;
int i = -68;
uint8 j = 17;
bool isEthereumCool = true;
address owner = msg.sender; //Ethereum address of the message sender
bytes32 bMsg = "hello";
string sMsg = "hello";
function getStateVariables() public view returns (uint, int, uint8, bool,
address, bytes32, string) {
return (x, i, j, isEthereumCool, owner, bMsg, sMsg);
}
}
The steps to deploy and test your smart contract are the same as the steps you learned in Chapter 7. Go to that chapter for details.
Before you can deploy and test your new smart contract, you need to add it to the migration JavaScript script. In VS Code, open the 2_contracts_migrations.js file in the Migrations directory. Then add the two lines with comments so your file looks this:
var HelloWorld = artifacts.require("HelloWorld");
var DataTypes = artifacts.require("DataTypes"); // Add this line
module.exports = function(deployer) {
deployer.deploy(HelloWorld);
deployer.deploy(DataTypes);// Add this line
};
Don’t forget to save your file after adding the new text!
Here are the steps you can use to deploy and test your new smart contract:
1. Make sure you have Ganache running. 2. In VS Code, click or tap the Terminal tab, type the following, and then
press Enter:
truffle deploy --reset
140 PART 3 Building Ethereum Distributed Blockchain Apps
3. Type truffle console and press Enter. 4. At the Truffle console prompt, type the following and press Enter:
DataTypes.deployed().then(function(instance) {return instance.getStateVariables() });
Figure 8-2 shows the values that your new smart contract returns. Truffle dis- plays the return values in an interesting way. Numbers are returned as BigNumber objects. You can call functions in a BigNumber library to convert them, but for now just read the values directly. For the numeric returned values, the first value, s: is the sign of the number, and the third value, c: is the unsigned value the function returned. Also note that the address and bytes32 values are in hexadecimal format.
Learning about Computation and Gas One of the difficulties encountered when writing distributed applications is bal- ancing the workload among participating nodes. The way blockchain technology is designed, all nodes do the same amount of work. In fact, all nodes duplicate the same work. This redundancy is necessary to ensure consensus among the nodes.
Workload balance isn’t a problem, but node overload is a big problem. Consider what would happen if a malicious user submitted a smart contract that consumed so much computing power that the node running the code couldn’t do anything else. That would be a denial of service (DoS) attack. And what’s worse, every node would be required to do the same amount of work. If malicious smart contracts were allowed to run, they could render the entire blockchain network unusable.
To avoid DoS attacks and to reduce the overall work network nodes have to carry out, Ethereum introduced the concept of paying for the work required to carry out
FIGURE 8-2: Smart contract return values.
CHAPTER 8 Learning about Smart Contracts 141
a transaction. Ethereum also includes a charge for storing data on the blockchain. These requirements encourage smart contract developers to use the blockchain only when necessary, thereby keeping the blockchain from growing unrestrained. Requiring transaction creators to pay for usage is a way of promoting conservative use of shared resources.
As you learned earlier, Ethereum measures the work required for operations by using gas. The amount of work required for each operation is used to calculate the fee to carry out the operations that make up a transaction. According to the Ethe- reum Yellow Paper (the formal Ethereum definition), every transaction requires a minimum of 21,000 gas units to complete.
The Ethereum Yellow Paper contains the formal definition of Ethereum. You can find the Yellow Paper by opening your browser and navigating to this address: https://github.com/ethereum/yellowpaper .
Miners are nodes on an Ethereum network that carry out the intensive mathemati- cal calculations to find a nonce value that satisfies the hash requirements for the block. You learn about mining, hashes, and nonce values in Chapter 2. Paying gas provides an incentive to miners to commit their computing power (and electricity) to the blockchain. Every user that submits a transaction pays a fee in gas, and miners in turn select transactions they think will be profitable and build new blocks with those transactions. The miner that is successful in solving the math- ematical puzzle gets the gas fees for the transactions in that block.
So, who pays all these fees to miners? Well, we all do! Every Ethereum transaction requires a small processing fee. Although this might sound like the middlemen that blockchain is supposed to replace, Ethereum fees are tiny compared to exist- ing systems in use today. However, even a relatively tiny Ethereum gas process can grow to be not so tiny during times of heavy network congestion.
Calculating gas fees requires several inputs, including gas price, gas limit, and gas (computation) cost. The user who submits a transaction (that is, initiates some action that invokes a smart contract) sets the highest acceptable gas price and the total limit of gas he or she will agree to pay. The total fee is the amount of gas used in the transaction multiplied by the gas price the miner charges. All of these val- ues can change from transaction to transaction. Table 8-5 lists the main compo- nents of gas charges and how they contribute to transaction fees.
If you want to know how much gas will cost, open your browser and navigate to https://ethgasstation.info. This web page shows gas statistics for recent Ethereum transactions. Figure 8-2 shows the recommended gas prices at the time of this writing. Note that a safe low gas price is 2.8 Gwei, the standard gas price is 4 Gwei, and if you want your transaction picked up quickly, you should set your gas price to 20 Gwei. 1 ETH is worth 1 billion (1,000,000,000) Gwei, so 4 Gwei is worth 0.000000004 ETH. At the time of this writing, 1 ETH is worth $89.40 USD,
142 PART 3 Building Ethereum Distributed Blockchain Apps
so the standard gas price of 4 Gwei (a standard gas price) is worth $ 0.0000003576. If a transaction requires a minimum of 21,000 Gwei, a transaction costs at least 0.0000003576 * 21,000 = $0.0075096. That’s less than a penny.
You can find the gas cost for operations in Ethereum in a spreadsheet located at: https://docs.google.com/spreadsheets/d/1m89CVujrQe5LAFJ8-YAUCc NK950dUzMQPMJBxRtGCqs/edit#gid=0 .
Although the minimum transaction fee doesn’t look like it is very expensive, the fees do add up if you waste computation. From a strict cost per computation, it isn’t hard to pay for your own node to carry out calculations. But what you’re paying for is transparency and validity among a large number of untrusted participants.
Exploring Access Modes and Visibility of Smart Contract Functions and Data
You can restrict who can invoke Solidity functions and who can access variable values. These access keywords are called visibility modifiers. You can use four visi- bility modifiers when you define functions and variables, as shown in Table 8-6.
TABLE 8-5 Ethereum Gas Charges Component Comments
Gas price The highest price per gas unit a transaction originator is willing to pay. Miners use this limit to determine if the transaction is worth including in a block. If the value is too low, the trans- action might not be profitable. If too many transactions are selected with very high gas prices, it might take too long to mine the block and the miner might lose to another node.
Gas limit The total number of gas units the transaction originator is willing to pay. It must be high enough to allow all operations to complete. If this value is too low, the EVM will terminate the transaction and undo all of its operations. Also, each block has a gas limit, so miners can’t just choose the transactions with very high gas limits — they have to choose transac- tions with gas limits that are cumulatively lower than the block gas limit.
Gas cost The cost of a single operation. For example, the ADD operation costs 3 gas and the MUL operation costs 5 gas.
Transaction fee
The total fee for computations in a transaction. The formula is: transaction fee = total gas cost * gas price.
Unused gas The amount of unused gas returned to the transaction originator if the gas limit for the transaction is greater than the actual gas cost.
CHAPTER 8 Learning about Smart Contracts 143
The Solidity compiler automatically creates a getter function for each public state variable, which provides an easy way to fetch the value of any variable. The name of the function is the same as the name of the variable. When the getter function is called, it returns the value stored in the state variable. So if you define a public state variable of type uint named myVar, the function myVar() will return a uint that is the current value of myVal.
Solidity visibility modifiers make it possible to write functions and define vari- ables that are available only to a specific subset of users. You might want some functions and variable to be available only to other functions in the same contract, say, for internal maintenance. In other cases, you might want other functions or variables to be available to anyone. A getter function (function that gets the value of some data item and returns it) is often a public function. That makes it avail- able to anyone, while an internal function that manages a contract’s date may be a private or internal function.
In addition to providing visibility modifiers, you can specify function access mod- ifiers. Access modifiers restrict how functions are allowed to access state variables. Older versions of Solidity used a single access modifier, constant, to indicate that a function did not modify any state variable. Starting with Solidity 0.4.17, two new access modifiers replace the constant modifier: view and pure. A function that exceeds its access modifier will result in a compiler error.
Here are the meanings of each access modifier:
» constant: This access modifier, which was deprecated in Solidity 0.4.17, was used to inform the compiler that the function would not modify any state variables.
» view: This access modifier, introduced in Solidity 0.4.17, is a replacement for constant and informs the compiler that the function will not modify any state variables.
TABLE 8-6 Solidity Visibility Modifiers Visibility What It Means for Functions What It Means for Variables
public Anyone can call this function. Anyone can access this variable’s value.
external Only external functions can call this function.
This doesn’t apply to state variables, and only external functions can access this local variable’s value.
internal Only functions in this contract and any con- tract deriving from it can call this function.
Only functions in this contract and any contract deriving from it can access this variable’s value.
private Only functions in this contract can call this function.
Only functions in this contract can access this variable’s value.
144 PART 3 Building Ethereum Distributed Blockchain Apps
» pure: This access modifier, introduced in Solidity 0.4.17, is more restrictive than view and informs the compiler that the function will not even read any state variables.
Controlling Execution Flow The simple smart contract code that you’ve seen so far doesn’t do much. It just executes from the top of the code to the bottom. Programs that do something use- ful have statements in them that alter the flow of execution based on input and calculations. Some statements, called conditional statements, enforce conditional expressions and execute only under certain circumstances. Other statements, called iteration statements or loops, repeat sections of code a certain number of times.
These types of statement are called flow of execution statements. Solidity implements many of the flow of executions statements you’ll find in JavaScript. Table 8-7 lists the conditional and iteration statements in Solidity.
TABLE 8-7 Solidity Conditional and Iteration Statements Statement What it does Example
if-else Executes a group of statements if a condition is true, and optionally executes another set of statements if the condition is false (else).
numDonuts = purchasedQty;
if (numDonuts >= 12)
giveDozenPrice = true;
else
giveDozenPrice = false;
While Executes a group of statements zero or more times until some condition is true (pre-test repetition structure.)
numDonuts = 1;
giveDozenPrice = false;
While (numDonuts < purchasedQty) {
numDonuts++;
if (numDonuts >= 12)
giveDozenPrice = true;
break;
}
CHAPTER 8 Learning about Smart Contracts 145
Handling Errors and Exceptions The last topic in your introduction to Solidity smart contract development is knowing how to handle errors and exceptions. By far the best way to handle errors is to avoid them in the first place. A naïve and unproductive way to handle errors is to leave it completely up to the user interface. A much better design practice is to anticipate as many errors and exceptions as possible and design your code to handle them. If you can envision an error during the design phase, you can develop code to handle it and even develop a test to ensure that your code handles it properly.
In versions of Solidity before 0.4.10, the only way to handle an error was to throw an exception when something bad happened. For example, pre 0.4.10 code to ensure that a code segment would run only if initiated by the code’s owner might look like this:
if (msg.sender != owner( { throw(); }))
Statement What it does Example
do-while Executes a group of statements one or more times until some condition is true (post-test repetition structure.) Note that a do-while loop always executes at least once.
numDonuts = 1;
giveDozenPrice = false;
do {
numDonuts++;
if (numDonuts >= 12)
giveDozenPrice = true;
break;
} (while numDonuts < purchasedQty);
for Executes a group of statements zero or more times until some condition is true (pre-test repetition structure.) This differs from a while loop in that the test condition is defined in the statement.
giveDozenPrice = false;
for (numDonuts=1; numDonuts<=purchasedDonuts; numDonuts++) {
if (numDonuts >= 12)
giveDozenPrice = true;
break;
}
146 PART 3 Building Ethereum Distributed Blockchain Apps
If a smart contract ever encountered a throw() function, all changes to state variables would be undone, the contract would return to the caller passing back an invalid opcode error, and all remaining gas would be used up. In other words, if your code encountered a throw() function, you would never get any gas back. And to make matters worse, you didn’t get anything done for that gas.
Starting with Solidity version 0.4.10, you have more options for handling error conditions. Current smart contracts can use the revert(), assert(), and require() functions to proactively handle errors. Table 8-8 lists each of the new guard functions and what each one does.
Although there is far more to Solidity than what you’ve seen here, you’ve learned enough to get started writing your own code. Before you know it, you’ll be ready to create your own Ethereum dApps.
TABLE 8-8 Error-handling Guard Functions Function What It Does Example
revert() Undoes all state changes, allows a return value, and refunds remaining gas to the caller. You should use this function to catch expected conditions that indicate that a transaction should be terminated.
if (msg.sender != owner( { revert(); }))
assert() Undoes all state changes and uses up all remaining gas — that is, like the legacy throw() function, does not return unused gas. You should never encounter this function in properly functioning code.
assert(msg.sender == owner);
require() Undoes all state changes, allows a return value, and refunds remaining gas to the caller. You should use this function to pro- actively execute code when prerequisite conditions have not been met.
require(msg.sender == owner);
CHAPTER 9 Writing Your Own Smart Contracts with Solidity 147
Chapter 9 Writing Your Own Smart Contracts with Solidity
You learn about the basics of developing Solidity smart contracts for Ethereum in Chapter 8. You also learn about difficulties encountered with traditional supply chain applications and how Ethereum can help address some of those problems. Developing distributed applications, or dApps, for the Ethereum blockchain may look similar to writing code in other languages, but it does have specific advantages over non-blockchain environments. However, you have to approach the software development process a little differently when working with blockchain.
Before starting to write a dApp for the Ethereum blockchain, make sure that you understand what your dApp should do and why a blockchain environment is a good fit. Getting these points cleared up in the beginning can help you avoid mis- takes that waste time and money. Knowing the tips and tricks of blockchain devel- opment before you start writing your own dApps will help you develop better software than just learning as you go.
Ethereum dApps focus on providing some functionality that interacts with data stored in the blockchain environment. Due to the design of blockchain technology, each interaction with the blockchain has an associated cost. Understanding how your dApp will have to pay for blockchain access is critical to getting it right the first time. In this chapter, you learn how to use Solidity to write effective smart contracts for the Ethereum blockchain environment.
IN THIS CHAPTER
» Creating your new smart contract
» Developing functions and events
» Protecting ownership and security
» Making your functions work
148 PART 3 Building Ethereum Distributed Blockchain Apps
Reviewing Supply Chain Design Specification
As you discover in Chapter 8, a supply chain is a framework that connects produc- ers to consumers and manages how products and services make their way toward the consumers. In simple cases such as a farmer’s market, consumers buy their produce directly from the growers. But in most other cases, at least one interme- diary helps get products from producers to consumers. Intermediaries can provide transportation, warehousing, retailing, and other value-added services.
Implementing a supply chain solution in a blockchain environment can reduce the overall cost of providing products and services to consumers and make the entire process more transparent. If you store every step of a product’s journey on the blockchain, anyone can track the product along its way.
The first step in developing a supply chain dApp is to look at the data and actions the dApp will need to provide the required functionality. For your supply chain dApp to do its job, you need at least four types of data. Here is a list of the types of data you’ll need:
» Products: This data uniquely identifies a specific product that is eventually bought by a consumer.
» Participants: This type of data is a description of all supply chain participants, including manufacturers, suppliers, shippers, and consumers.
» Registrations: This type of data is a snapshot of which participant owns a product at a specific point in time. Registrations track products along the supply chain.
» Payment token: Participants use payment tokens to pay one another for ownership changes of products. For example, a supplier can purchase a product from a manufacturer and use a payment token to pay the manufacturer.
To provide minimal functionality, your supply chain dApp needs to include the following capabilities:
» Initialize tokens: Establish an initial pool of payment tokens. » Transfer tokens: Move tokens between accounts (that is, pay for products
with tokens).
» Authorize token payments: Allow an account to transfer tokens on behalf of another account.