7   Ethereum Application Best Practices

Ethereum Blockchain Development

As we write this book in late 2017, integrated blockchain development environments (IDEs) are still emerging. Truffle (http://truffleframework.com/) is a development environment, testing framework, and asset pipeline for Ethereum.

Truffle provides:

•   Built-in smart contract compilation, linking, deployment, and binary management

•   Automated contract testing

•   Scriptable, extensible deployment and migration

•   Network management for deploying to any number of public and private networks

•   Package management with EthPM and NPM, using the ERC190 standard

•   Interactive console for direct contract communication

•   The ability to build pipeline with configuration and tight integration

•   Script runner that executes within a Truffle environment

Setting Up the Development Environment for Truffle

There are technical requirements to work with Truffle. You should install the following:

•   Node.js (https://nodejs.org/en/)

•   Git (https://git-scm.com/)

When developing your Truffle-based application, it is recommended that you use the EthereumJS TestRPC (https://github.com/ethereumjs/testrpc). It’s a complete blockchain-in-memory that runs only on your development machine. It processes transactions instantly instead of waiting for the default blocktime—so you can test that your code works quickly—and it tells you immediately when your smart contracts run into errors.

You need the following two commands to install the TestRPC for Ethereum and Truffle:

Images

Set Up a Truffle Project

To verify it installed, type

truffle list

in a console window to list all Truffle commands.

Then create a new project directory, cd to it and type:

truffle init

By default, truffle init gives you a set of example contracts (MetaCoin and ConvertLib) which act like a simple alt-coin built on top of Ethereum. You can use these contracts to learn quickly while navigating through the Getting Started guide, or delete these files and build a project of your own.

By default, truffle init creates a simple project for you so you can get familiar with writing, compiling, and deploying Solidity-based smart contracts.

Now start a client node in a new console window by running:

testrpc

Then in another command prompt window run the following commands to compile and deploy the code:

Images

Truffle Directory Structure

The default Truffle directory structure contains the following:

•   /contracts: Contains the Solidity source files for our smart contracts.

•   /migrations: Truffle uses a migration system to handle smart contract deployments. A migration is an additional special smart contract that keeps track of changes.

•   /test: Contains both JavaScript and Solidity tests for our smart contracts.

•   truffle.js: Truffle configuration file.

Beyond this brief overview, go to http://truffleframework.com/tutorials/ to try the latest Truffle tutorials and documentation to continue with your Ethereum blockchain development.

Ethereum Blockchain Development: Best Practices

Before plunging into code design and implementation, let’s recap the properties that define the possibilities and constraints we need to consider when making contracts and applications and systems that utilize them.

The Ethereum blockchain is a second-generation blockchain. It contains all the properties of the first-generation blockchain, like an immutable block of transactions, proof of work, and cryptographic verification. In addition, the Ethereum blockchain contains a Turing complete virtual machine or EVM (Ethereum Virtual Machine). This allows for much richer applications than what Bitcoin has with transactions. The EVM is a simple 256-bit stack machine with a stack size of 1024. EVM code is deployed as smart contracts. All code is committed to the blockchain and accessed from the EVM as virtual ROM. Storage is word-addressable word arrays persisted as part of the blockchain system state.

The EVM can be considered a single instance of a worldwide virtual machine, synchronized across all nodes in the network. All code execution (transactions and smart contract function calls) is started by an external user—smart contracts do not execute by themselves. A code execution is considered a single transaction. Either all code is executed and the new state is persisted on the blockchain, or an error occurs and everything is reverted (except the mining reward), just like an ACID transaction in a relational database management system (RDBMS).

The EVM can be perceived as a cloud computer service, where the payment and execution are integrated. To execute EVM code and change blockchain state and storage, cash is provided as “gas” to the execution call. However, there is only a limited amount of execution gas available in each block. This implies that there is a finite and restricted amount of code that can be executed and storage to be changed in a single transaction. This is in sharp contrast to modern development where you have access to an almost infinite amount of resources at hand in the cloud.

The best mindset to have when programming smart contracts is to consider it as programming a microcontroller that is launched into space. There are very limited resources to execute, limited gas, and limited memory and stack size. If there is an error (bug) in the code, it’s hard to fix, and one needs to think of the entire life cycle, with all of the future security and operational needs of the contract taken into consideration.

Blockchain Technologies

The EVM itself is only part of the whole decentralized ecosystem. In order to interact with and execute smart contracts, other components are needed. As mentioned in Chapter 3 on blockchain technology use cases, Web 3.0 components include:

•   Dapps: decentralized applications

•   Contracts: decentralized logic

•   Swarm: decentralized storage

•   Whisper: decentralized messaging

The simplest solution is a decentralized application (dapp). This form does not need a central server, only code running in a browser that interacts with the user and an underlying smart contract (or set of smart contracts). The browser code (web application) can be distributed either from a normal web server or from decentralized storage like Swarm or InterPlanetary File System (IPFS). For the remainder of this chapter we will mostly deal with applications that interact with traditional systems.

Solidity Basics Continued

We covered Solidity and the language constructs in Chapter 6. Now let’s continue with a review of the basic language elements. Here is a contract showing constructor, modifier, and events for the Ownable pattern.

Images

This is a good, simple base contract defining an onlyOwner modifier and function that allows the ownership to be transferred and issues an event when the ownership is changed. However, the transferOwnership function contains a danger. If it is called with a wrong address, the control of the contract is lost forever. One way of dealing with this is to transfer the ownership in a two-phase push/pull pattern. First, the old owner “pushes” a newOwner by calling the transferOwnership function. This does not transfer the ownership right away but rather stores the address in a contract variable in a pending state. Second, the new owner has to accept the ownership by calling acceptOwnership. This will “pull” the ownership to the new owner. Note that only the newOwner specified in the transferOwnership function can actually claim the new ownership, and the ownership is actually transferred only when the newOwner has called the acceptOwnership function. If the newOwner address is wrong or newOwner has lost access to the account, then the ownership is never transferred, thus avoiding the potential predicament from the first version of the contract.

In general, it is good practice to use a two-phase push/pull when dealing with irreversible functions with high implications like transfer of ownership, refunding, etc.

Images

Images

Calling Contracts from Contracts

A unique aspect of the EVM environment is the concepts of gas and value. As mentioned, the EVM can be conceived as a cloud computing service, where you need to pass payment to each call to pay for cloud execution. The payment for execution is added as gas, and the payment passed to accounts is added as value. As discussed, gas has a wei price (gasPrice) and can be calculated as a wei amount = gas*gasPrice. Both gas*gasPrice and value are taken from the caller’s balance.

Consider the following contract:

Images

Then to instantiate it from within another contract as

A a = new A(…);

if you simply now call

a.trade();

it will by default not pass any value to the function. You need to add a .value(...) argument to the calls like

a.trade.value(somevalue)();

When you call a function on a smart contract with a value, that contract will then own the value sent. It can in turn call functions on other contracts, transferring value to these and so on.

Let’s see that in action. Consider a contract B:

Images

and instantiate B as

B b = new B(a,wallet,10);

and then call

a.trade.value(sometradevalue)();

Within the trade function of B that now has sometradevalue, you can see an example of splitting this value passed to b.trade into a call to a.trade() with 90 percent of the value and passing 10 percent of the value to a commission wallet.

If you want to create a cloud service for the blockchain contracts that binds outside the EVM, this is a way to get paid by the caller directly, thus avoiding separate invoicing and so on.

However, please note that the .value call by default passes on all available (remaining) gas and should be considered unsafe against reentrancy. So be careful if you don’t control the contract being called.

You can specify the amount of gas passed to a function by adding .gas(someGasAmount) to the function call:

a.trade.value(msg.value - commission).gas(40000)();

Calling address.transfer only passes 23000 gas. That is insufficient to do any reentrancy but might be insufficient for complex function () payable routines to complete.

Pitfall: Remember to forward gas and ether between contracts when calling payable functions.

Handling Events

EVM events are a central part of the smart contract ecosystem. We saw an example of an event in the Owner contract where the contract issues a TransferOwnership event each time the owner changes

Events allow users and especially applications to monitor smart contract changes on the blockchain. This is done by specifying filters and applying them on a blockchain node. Events can be filtered on topics, values, and block intervals, thus listing to new events or scanning through old events.

Users can be notified about changes to contracts they have interest in, such as changes to ownership, ERC20 tokens, changes to balances, notification of multisig wallets pending confirmations, etc. Likewise, enterprise applications that integrate to business logic and process flows in smart contracts can be notified when enterprise application actions are needed.

User actions on smart contracts can trigger enterprise services, and enterprise status updates on smart contracts can notify users, just like events in regular applications. In enterprise applications, a process needs to be put in place for events to be captured. Consider the event

event MyEvent(address indexed myidx, uint myval);

Adding indexed to the event argument myidx makes the event searchable through filters using myidx values.

In C#, using the Nethereum package monitoring for live events might look like this:

Images

Images

The example below will set up an event listener that calls two functions whenever a new MyEvent event is seen on the blockchain.

Images

In NodeJS the syntax is a little simpler:

Images

If the service needs to process events from the past, they can be filtered by block interval as well as by filters on indexed parameters.

Images

If an enterprise system needs to handle all events issued from a contract, it’s a good idea to add a sequence number on each event.

event MyEvent(uint indexed eventId, address indexed myidx, uint myval);

This allows the enterprise system to easily track whether all events are handled and in case of breakdown efficiently recover/reprocess the missing events.

Remember that enterprise system event handlers can also call functions on contracts. This makes EVM events behave just like other kinds of events, thus allowing mixed cascade triggers through different systems. Imagine the following system flow (see Figure 7-1).

Images

FIGURE 7-1   Example of enterprise system flow involving smart contracts

1.   A user (web) app calls a function on a smart contract.

2.   The smart contract function generates an EVM event.

3.   This event is captured by a server monitor.

4.   The monitor starts a job on a third-party system.

5.   Retrieve the result from the third party when the job completes or some condition is met.

6.   The monitor calls a function on a smart contract with the outcome and changes the status.

7.   The smart contract function generates an event containing the outcome and the new status.

8.   The user app captures this event and updates the UI with the outcome and new status.

As seen, this allows building of complex integrated systems without building complex infrastructures between trusted parties or agreements of cost share. It solely uses the blockchain of the infrastructure and payment platform. The user app and the server systems are independent of each other and do not need to establish complex agreements.

In a generalized form the server monitor acts like an intermediary between the blockchain and the real world; this is often referred to as an oracle.

As discussed, a smart contract can’t trigger itself, since the blockchain needs to be deterministic. So it cannot depend upon or access the real world directly from the EVM. It needs to be activated by an external agent, as illustrated in Figure 7-2. An agent can be either a user or an oracle. Oracles comes in two forms. They can be “callable” from the smart contract by generating an event with a request/reply interaction as shown in Figure 7-1. Or they can be trigger based where the oracle calls the smart contract when certain conditions are met. This could be when a currency hits a certain price or when an IoT sensor detects a certain value.

Images

FIGURE 7-2   Application with a user, a smart contract, and an oracle

To include a third-party oracle in the smart contract flow, it needs to be trustworthy and reliable since its interaction with the blockchain is immutable and hence irreversible.

Smart Contract Design

All the virtues of modern design certainly apply to making smart contracts. In fact, even more so, because of the immutable nature of the blockchain: clear design, well-thought-out security, thorough tests, and life cycle management are musts. In this section, we will elaborate on some of the important virtues.

Modules and Interfaces

For traditional coding, it is a widespread best practice to divide the code into sections representing separation of concerns. This is especially relevant in writing smart contracts. There already exist a number of libraries containing typical modules that are needed when writing a contract. And it is preferable to reuse well-established modules. A good example of this is OpenZeppelin (https://github.com/OpenZeppelin/zeppelin-solidity). Their tagline formulates it very well: “Reduce the risk of vulnerabilities in your applications by using standard, tested, and community-reviewed code.”

Using such modules whenever possible reduces the risk of error and frees valuable time to focus on the unique features of the contracts at hand. Even when a module needs to be modified to fit some particular needs, reuse of the corresponding tests to ensure nothing gets broken is highly recommended.

Don’t over-engineer the contract or dazzle with fanciful coding techniques. Keep it simple, stupid—especially because most contracts used by the public are going to have the corresponding source attached on the blockchain for anybody to inspect and validate. Having a clear, simple contract that is easy to understand gains more trust and is actually less likely to contain flaws than a large over-engineered contract doing way more than actually needed, as its attach vector is much smaller.

Security and Roles

When designing smart contracts, it is important to think about security from the very start. Since contracts are public and visible on the blockchain, everybody can potentially call every function. Even if you do not submit the source code, there is still the bytecode so everyone with the right understanding of the EVM and proper endurance can figure out what the contract does and call it, so don’t count on security by obscurity.

Most contracts implement the owner pattern that can be used to restrict the highest state “administrator” change functions, like setup, start, stop, and kill.

Consider the kill function:

Images

Using the modifier signature, it becomes clear that the function is only allowed to be called by the owner and the function body contains only the business code. However, the private key of the owner should be stored somewhere safe and only used in major life cycle events for the contract.

More operational functions should be modularized and restricted to special roles different from the owner. The owner should then delegate these role rights to other addresses. The specialized roles often run on web services or staff computers, and need to contain the private key for their role address in order to execute. If a system is hacked and the private key of a role gets compromised, the implications are confined to that role’s operations, and the system can more easily be recovered by the owner by changing the compromised role address.

Examples of roles could be:

•   Minter: A role capable of minting new tokens in a token contract

•   MigrationMaster: A role responsible for the migration process from an old contract to a new contract

•   InvitedInvestor: A role given to invited addresses to make investments in a restricted ICO

•   Trader/Executer: A role that executes trades or orders on behalf of customers

Each role can either be a single address role or multiple addresses, often referred to as whitelisted addresses.

As we saw in the Ownable contract, a modifier for a single address role can be as simple as

modifier onlyRole { require(msg.sender == roleAddress); _; }

A multiple address role can be implemented as a mapping like

Images

And then the modifier would change to this:

modifier onlyRole { require(roleWhitelist[msg.sender]); _; }

The use of access control should not be implemented as part of the function itself, but the use of clearly defined modifiers on the function header is highly recommended. This is because it separates the access control logic from the function and also because it makes the functions easier to read since they only contain the business logic.

Single Contract Design

As a contract evolves and has more and more features added to it, it’s easy to end up with a fat contract that does way too much and becomes difficult to manage. If nothing else is done, the development will end abruptly one day, simply because the combined cost of code deposit and create execution exceeds the total available gas within a single block execution. This is called block gas limit (BGL). The BGL on the public net is currently 4,712,388.

A way to keep an eye on this is to look at the gas estimates in the json output of the compilation. As seen here, the sum of the two numbers (code deposit and execution) exceeds BGL, so this contract will not be able to deploy.

Images

In general, if the contract creation estimate comes anywhere near to BGL, the contract design should be revised.

Linked Contracts

Instead of putting all functionality into a single contract, it’s often advisable to divide it into several contracts that act together. Ideally you can reuse already existing base contracts that have been well designed, well tested, and have stood the test of time. Such contracts could be standard tokens, multisig wallets, etc.

Let’s say that you want to build an ICO contract, where investors are invited to buy tokens at a fixed price for a limited period of time. You want to collect all the ether into a secure wallet, and you want all the tokens to reside in a standard ERC20 token that eventually will be freely tradable on exchanges after the ICO. When the ICO is over and validated, the ICO contract is in fact not needed anymore as it has completed its life cycle.

How would you construct such an ICO contract system?

Well, there are a number of implementations of both multisig wallets and standard contracts, so no need to write those. Instead, we concentrate on writing our particular ICO process and then just bind it to a standard multisig wallet and a standard token contract.

Each contract is deployed as a separate transaction so the size of the total contract system can be much larger that a single BGL. Only the individual contracts need to be below BGL. Here is the pseudocode to create the contracts and bind them together.

Images

Images

Once the contracts are deployed and connected, the ICO sales can start (here shown as explicit functions, often the ICO runs within a specified blockNumber range).

Images

When the ICO is complete, the ICO owner can request the funds.

Images

The auditor can validate the ICO process and state and release the funds to the ICO owner.

Images

Now that the ICO is complete and the shares are stored in the standard contract, the ICO crowd contract can be destroyed.

Images

User-Specific Contracts

Previously we saw an example where several (standard) contracts worked in conjunction, forming the whole system. If we want each user to have its own individual settings and peculiarities, then instead of polluting the core contracts with this complexity, it might be better to keep them as user-specific contracts. As we discussed earlier, polymorphism works well in Solidity with the interface specification.

Imagine we have a contract system that handles assets that is accessed within the main contract master only using an asset interface like this:

Images

Then different asset implementations can be developed even after the master contract is deployed.

Images

Images

Some later implementation of an asset contract:

Images

This allows for the following deploy sequence.

Deploy master:

Master m = new Master();

Develop MyAsset, deploy it, and bind it to master:

Images

Later, develop MyAsset2, deploy it, and bind it to master:

Images

Call some actions on the assets:

Images

This also demonstrates that a system of linked contracts can be designed to upgrade and extend over time without a total redeployment—in this example, especially without redeployment of master, which address might be embedded in a lot of systems and users’ wallets.

Handling Persistent Contract Addresses

In some situations, it may be desirable to keep a persistent contract address while maintaining the possibility of changing the implementation. For instance, if the contract address is imbedded in many other systems or registered with many users, changing the instance address may be an insurmountable endeavor and involve unmanageable synchronization issues.

This problem can be resolved by introducing a proxy contract that wraps the implementation contract. This is a well-known traditional technique that is especially relevant for this smart contract issue.

An implementation of a proxy goes like this:

You start with the interface of the desired functionality.

Images

Implement the proxy contract as callthroughs to the implementation contract functions.

The log function is a helper function to issue events on the proxy contract level.

Images

Images

The implementation class that implements the actual doSomething function is only allowed to be called from the proxy call.

Images

Set up the proxy.

Images

Correct call to implementation as a call to the proxy contract.

proxy.doSomething(this,0xFFF0);

This is not allowed:

Images

If a change is needed, then change the implementation to a new class.

proxy.setImplementation(new ContractImplementation2(proxy))

Now the same proxy call will call the new implementation.

proxy.doSomething(this,0xFFF0);

Halting a Contract

If an unforeseen event happens, like a severe bug in the EVM or the discovery of a vulnerability within the code, the assets within the contract might be in danger. In this case it will be a good idea to have a halt functionally that stops most (but not all) of the activity within the contract while the situation is evaluated.

This can easily be accomplished by adding a notHalted modifier to the functions.

Images

From a security perspective, the decision to halt the contract should be available for central system operators and security agencies, while the unhalt should be restricted to the owner—much like a normal emergency button where many people can stop the machinery, but only a few can start it again. Better safe than sorry.

Images

Smart Contract Life Cycle: Migration

If case of bugs, vulnerabilities, or the need to add some new features, a new contract is needed and should replace the old contract.

The basic idea with a smart contract migration is similar to a normal application migration. The state of the old smart contract is transferred securely to a new smart contract, and the old contract becomes inert or is destroyed.

Here we have a trust issue. In the best-case scenario, the benign contract owner discovers a security issue, fixes the error and deploys a new contract, and as migration master puts the original smart contract into migration mode pointing to the new contract. Then each stakeholder transfers their state from the old contract to the new contract—that is, for a token contract the user transfers their tokens from the old contract to the new contract, and so on. Once all states (tokens, etc.) are transferred, the old contract can be destroyed or simply become an inactive void instance. Note that the user transfers the state, not the contract owner.

A migration interface could look like this:

Images

When implementing the transfer function, we must ensure that it can only be called from the original smart contract.

Images

Images

Smart Contract Interaction with Users and Enterprise Applications

As we discussed earlier, smart contracts and blockchain are only a part of a whole solution. If the bulk of the business logic is within the contract(s) and only a simple user application is needed, it can easily be implemented as a dapp. In an enterprise solution, smart contracts can be thought of as an asynchronous web service or a batch job component of the system.

When integrating blockchains into an existing enterprise application, in many cases it is a good idea to expose the blockchain interaction through a standard web service. In this way, the “old” enterprise application developers don’t need to deal with or understand the particulars of blockchain interaction. From their perspective, it’s just an additional third-party component with normal async WEB-API behavior.

Debugging Your Smart Contract

Debugging is an essential part of application development. This is true for smart contract development as well. Unfortunately, in Solidity the throw keyword or calling revert() does not take any argument and cannot return any error number or error text. In non-trivial functions there can be several reasons for failure, and as a newbie or with complex contracts it can be difficult to quickly identify the reason for failure. This is a limitation of the current environment both during development debugging and debugging production problems. We hope this will be addressed in future versions of EVM and Solidity.

Pitfall: The low-level functions send, call, delegatecall,and callcode return false in case of an error; they do not throw an error. Take extra care when using these functions and test thoroughly.

Debugging Using Remix

As covered in Chapter 6, Remix Solidity IDE is one of the best debugging tools presently available. This tool allows you to code Solidity contracts, compile them, analyze them, and even run them. It is a great tool to try things out and to get acquainted with the mechanics and quirks of the Solidity and EVM environment. It also has a JavaScript VM that allows you to step through the function calls and identify problems and states, and is an indispensable tool to find those bugs that just elude your comprehension. Unfortunately, it currently only works well for small code bases. For large code bases containing many contracts, Remix becomes slow and even unworkable.

Debugging Using Events

Another way to debug your code is to (mis)use an event. If you add an event like this one,

event Debug(string text, uint value);

then you can add calls like this to your code:

Images

You can then examine the values from the event log within your test environment.

Notice the premature return to prevent having the function throw, because otherwise all is reverted and no events are logged. It is the nearest thing to a log.writeline you can have in EVM. We often use this approach if we inadvertently introduce a throw bug that reveals itself within a complex Truffle test set, where the reason for the error is not obvious and is too cumbersome to reproduce in Remix.

Smart Contract Validation

Testing smart contracts is especially important since they cannot be changed once deployed. Therefore you definitely want to test and review every possible scenario that can unfold in the production network, including what happens when hackers are trying to steal the assets they contain.

Types of Tests

The relevant tests can be divided into separate types and domains and are described individually.

Functional Tests

Firstly, you have the traditional CRUD-like function tests that ensure you can create, read, update, and delete entries, roles, users, etc., within your contract. This is just business as usual.

Normal Life Cycle Flow Tests

These tests run through the different stages of a contract such as creating, preparing, running, halting, and terminating. They test that the contract can change stages correctly all the way from create to destroy. For each stage, it is tested that the functions for that stage can be called but also that functions for other stages cannot be called—for example, testing that init functions cannot be called in the running stage.

Vulnerability Tests

There are known vulnerabilities that need to be mitigated and tested.

Overflow and Underflow Attacks

Numbers like uint don’t fail on overflow or underflow like most other high-level languages, but just wrap around, maxsize assembler style. Why this design decision was made is beyond us.

Consider the code:

Images

Here a – 2 performed an underflow and becomes 115792089237316195423570985008687907853269984665640564039457584007913129639935.

And b + 2 performs an overflow and becomes 1. The same condition can be found for most other operations.

This constitutes an attack vector that may allow a user to call a function with a carefully designed value that triggers an arithmetic error, i.e., assigns a very large account value for an address. Normally these kinds of errors are mitigated by safe numeric operations like this:

Images

and used in contracts like this:

Images

We don’t understand why this is not the default behavior since everyone has to add it to their contract code.

Recursive Call Attacks, Reentrancy Exploit

Consider this code:

Images

This function withdraws all assets from an account (3), sends them to its owner (4), and updates the account balance to zero (5). However, since the call.value potentially hits a function at a sender’s contract, this function can call the withdraw function again before it is set to 0, thus withdrawing the balance value again and again until the original contract is depleted.

Note that this attack might also be executed by calling a sequence of other functions on the original contract that exploit an incomplete state change. Normally this issue is mitigated by applying the Checks-Effects-Interaction pattern—that is:

1.   First Check all preconditions,

2.   Then perform all the Effects on the global state,

3.   And finally do Interactions with other contracts

Images

Test Contract at Maximum Capacity

One consequence of the limited amount of gas in a block (BGL) is that you need to think about gas usage of the different functions when you keep adding items to the contract system. What happens at maximum capacity of the contract? Will the contract functions experience gas overflows at maximum capacity?

Loops and recursive calls are especially critical. Will the operations have enough gas to execute in worst-case conditions? Try to identify the longest run for loops and the deepest recursive call. In fact, it’s best to avoid them altogether if possible. If that is not possible, ensure that they will have a defined upper limit within BGL.

Dry Run Using Private Nets

At the end of the day, testing with TestRPC and JavaScript VM isn’t the real McCoy. To be blunt, each test daemon implements its own particular quirks and errors that are different from the quirks and errors in the production environment.

Therefore, it is prudent to do a dry run of the intended usage (and misusage) using the real daemon, such as Geth or Parity. The actual code is the same in all environments. The only difference between executing in dev, testnet, or production is the chainId. In many cases, especially during development, it is desirable to run in a private blockchain. You don’t want to plaster testnet or production with half-baked contracts in your name. Fortunately, it’s rather easy to launch a private blockchain. Here it’s shown for Geth.

In a test cycle, it’s preferable to start at the same state every time, so first delete all old chain information.

Images

Then initialize a new blockchain using a configuration file.

geth --datadir=privChain init genesis_dev.json

Finally, launch a node running your private blockchain.

Images

If you want your private node to run simultaneously with other nodes, add specification of the modified port like this:

--port 30304 --rpcport=8551 --ipcpath “devgeth.ipc”

Then connect to the private node using the URL, e.g., http://localhost:8551.

The configuration file that reflects production details might look like this:

Images

Most are default values that should match production. The main values to set are the chainId and the alloc section where addresses can be prefilled with ether.

Autopsy of a Wallet Bug

On July 19, 2017, it was discovered that somebody had heisted three Parity multisig wallets. This resulted in a race where the community, with the White Hat Group (WHG) in front, tried to identify and mitigate the issue.

The constructor function looks like this:

Images

As you can see, it delegates the initialization to a _walletLibrary function initWallet by constructing the call directly in memory using assembly opcodes. This code is not for the fainthearted. This is pure brain surgery—you don’t want to sneeze while writing this code.

Also, the wallet default function uses the fact that if you call a function not defined in the wallet contract itself, it will be caught by the default function.

The delegatecall to _walletLibrary is called with the original function call data. This means that you will have implicit access to all the functions in _walletLibrary as they were implemented directly in the wallet contract. This is a very powerful mechanism but potentially also very dangerous.

Images

One of the functions in the WalletLibrary is the init helper function initWallet we saw called in the constructor of the wallet, and that is what it was meant for. However, since there are no checks or modifiers on it, and with the delegatecall call in the default function, this unfortunately means that everybody can call the initWallet at every moment of the wallet life cycle. Thus, they gain owner control over the multisig wallet, making transferring money out of it like stealing candy from a baby.

Images

The fix was very simple, by just adding the missing modifier to control that the init helper functions can only be called in the initialization phase.

Images

This clearly illustrates how important it is to think very thoroughly about each and every function:

•   What are the preconditions?

•   Who is allowed to call it?

•   When in the life cycle is it allowed to be called?

Moreover, test that when you call it at the right moment as the rightful operator, it indeed does what it is supposed to do (normal unit testing). Even more important, test that if you are not the rightful operator or call it in the wrong state, it will do no harm and will in fact be rejected (security testing).

Writing thorough test cases is a job magnitude larger and more comprehensive than writing the contract itself.

The Future

One part of the smart contract development system that lags behind is automated testing. Using and extending the NatSpec comments could easily facilitate the generation of skeleton testing code that would significantly reduce the time spent on setting up unit and security testing.

However, the elephant in the room is the lack of scalability, which limits wide adaptation. It also makes blockchain vulnerable to denial-of-service attacks by flooding it with spam transactions. Also, to support microtransactions the transaction price needs to be lower. To become a universal and scalable platform, this problem has to be solved. One solution that tries to address the problem is the Lightning Network–like implementation for Ethereum called the Raiden Network. This work-in-progress project supplements the Ethereum blockchain with an offline chain to settle microtransactions. However, it requires preallocation of tokens/ether that are taken offline by transferring them to the Raiden Network before they can be utilized. This introduces a locking of assets offchain equal to the total liquidity needed. Also, it doesn’t solve the scalability of general smart contracts. Other types of blockchain projects try to address this problem too. One example is the EOS Project, a generalized platform based on features from Steemit and Ethereum. This platform has no transaction fee and offers three-second block transactions without congestion by allowing parallelism in block execution and thereby introducing horizontal scalability beyond the 100,000 transaction per second mark.

Another example is the IOTA project, which is designed directly for massive microtransactions between IoT devices. In IOTA when you need to add a transaction, you need to validate two other transactions and check for conflicts before submitting into a tangle (connected graph), so you become your own miner, thus eliminating the need to pay somebody else for the validation. Strictly speaking, IOTA is not a chain of blocks containing transactions but rather a mesh of linked transactions. On the roadmap, IOTA will include smart contracts and oracles.

Absolute privacy is also an issue. Even though addresses are anonymous in the sense that the identities behind them are not normally registered, all transactions and balances are publicly available by design. If you use ether to pay to an address that uses some kind of KYC, either directly or indirectly, it is possible to back-trace your spending habits and wealth. Monero is an example of a blockchain that focuses on complete anonymity that is secure, private, and untraceable. It uses ring signatures where decoy addresses are added to the transaction, making it possible to hide the origin of a transaction. With stealth addresses (one-time addresses), the destination address is obscured. By using ring confidential transactions, the value of the transactions is hidden by cryptographical algorithms, but still verifiable. All in all, it ensures complete anonymity end to end. As yet they don’t have Lightning Network or smart contracts, but those are on the roadmap.

Ripple XRP is a private centralized permission-based blockchain that acts like a worldwide transfer between bank accounts à la SWIFT. It’s designed to scale to the same performance as VISA by implementing a peer-to-peer ledger network with a distributed agreement protocol. Instead of including the smart contract into the core blockchain, Ripple decided to implement a separate platform, Codius, for the smart contract and oracle part, which also allows cross-blockchain applications.

When looking at roadmaps for the different blockchains, it’s clear that they have many of the same properties in mind. These include scaling the number of transactions to allow both volume and micropayments, as well as the inclusion of smart contracts and integration of oracles. All of these are where the best practices in this chapter will come in handy.

Summary

As we have seen in this chapter, the EVM provides a rich environment that enables development of solutions ranging from simple dapps, over simple interactions with oracles to fetch external information, all the way to full stack enterprise solutions. The smart contract platform includes all the features for creating modern code with multiple contracts calling and interaction with each other, including producing events to external systems. Also, we have recognized the importance of clear design in terms of modularity, roles and security, and life cycle management. Finally, because of blockchain’s immutable nature, testing and validating of smart contracts need special attention prior to deployment on the blockchain.

..................Content has been hidden....................

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