In this section we will explore the world of Decentralized Applications or DApps. From the early days of Ethereum, the founders' vision was much broader than "smart contracts": no less than reinventing the web and creating a new world of DApps, aptly called web3. Smart contracts are a way to decentralize the controlling logic (and payment functions) of applications. Web3 DApps are about decentralizing all other aspects of an application: storage, messaging, naming etc.
While decentralized apps describe an audacious vision of the future, the term DApp is often applied to projects that fall short of that vision. In fact, any smart contract with a web front end is called a DApp. Some of these are highly centralized applications (CApps?) in every way, yet they get called "DApps" anyway. Beware of false DApps!
In this section, we will also develop and deploy a decentralized auction platform, as an example DApp. You can find the source code for that in the book’s repository under code/auction_dapp. We will look at each apsect of an auction application and see how we can decentralize the application as much as possible.
A Decentralized Application, or DApp, is an application which is mostly or entirely decentralized.
Consider all the possible aspects of an application that may be decentralized:
-
Front-end software
-
Back-end software (logic)
-
Data storage
-
Name resolution
-
Message communications
Each of these can be somewhat centralized or somewhat decentralized. For example, a front-end can be developed as a proprietary application, or as an open web application. The back-end and storage can be on private servers and proprietary databases, or a smart contract and P2P storage.
There are many advantages to creating a DApp that a typical centralized architecture can not provide:
1) Resiliency: by having the business-logic controlled by a smart contract, a DApp back-end will be fully distributed and managed on a blockchain platform. Unlike deploying an application on a centralized server, a DApp will have no downtime and will continue to persist as long as the platform is still operating.
2) Transparency: the on-chain nature of a DApp allows everyone to inspect the code and be more sure about its function. On the same note, any interaction with the the DApp will be stored forever in the blockchain.
3) Censorship Resistance: as long as a user has access to an Ethereum node (running one if necessary), the user will always be able to interact with a DApp without interference from any centralized control. No service provider, or even the owner of the smart contract, could alter the code once it is deployed on the network.
In the Ethereum ecosystem as it stands today, there are very few trully decentralized apps - most still rely on centralized service and servers for some part of their operation. In the future, we expect that it will be possible for every part of any DApp to be operated in a fully decentralized way.
In a DApp, smart contracts are used to store the business logic (program code) and the related state of your application. You can think of a smart contract replacing a server-side (a.k.a. "back end") component in a regular application. This is an oversimplification, of course. One of the main differences is that any computation executed in a smart contract is very expensive and so should be kept as minimal as possible. It is therefore important to identify which aspects of the application need a trusted and decentralized execution platform.
Ethereum smart contracts allow you to build almost arbitrarily complex architectures in which a network of smart contracts call and pass data between each other, reading and writing their own state variables as they go. We have to add "almost" in our description, because the amount of computation that can be done in one transaction will always be limited to some degree, as specified by the block gas limit. After deploying your smart contract, your business logic could well be used by many other developers in the future.
One major consideration of smart contract architecture design is the inability to change the code of a smart contract once it is deployed. It can be deleted if it is programmed with an accessible SELFDESTRUCT opcode, but other than complete removal, the code cannot be changed in any way.
The second major consideration of smart contract architecture design is DApp size; a really large monolithic smart contract may cost a lot of gas to deploy and use. Therefore, some applications may choose to have off chain computation and an external data source. Keep in mind, however, that having the core business logic of the DApp be dependent on external data (e.g. from a centralized server) would mean your users will have to trust these external resources.
Unlike the business logic of the DApp that requires a developer to understand the EVM and new languages such as Solidity, the client side interface of a DApp can use basic web technologies (HTML, CSS, JavaScript, etc). This allows a traditional web developer to utilize the tools, libraries and frameworks they are familiar with using on a regular basis. Interactions with Ethereum, such as signing messages, sending transactions and key management are often conducted through the web browser, via an extension such as MetaMask.
Although it is possible to create a mobile DApp as well, currently there are few resources to help create mobile DApp front-ends, mainly due to the lack of mobile clients that can serve as a light client with key management functionality.
The front-end is usually linked to Ethereum via the web3.js Javascript library, which is bundled with the front-end resources and served to a browser by a web server.
Due to high gas costs and the currently low block gas limit, smart contracts are not suited to store or process large amounts of data. Hence, most DApps will utilize off-chain data storage services, meaning they store the bulky data off the Ethereum chain, on a data storage platform. That data storage platform can be centralized, such as a database and web server hosted by a company. Or, the data can be decentralized, stored on a P2P platform such as the Interplanetary File System (IPFS), or Ethereum’s own Swarm platform.
Decentralized P2P storage is ideal for storing and distributing large static assets such as images, videos, and the resources of the application’s front-end web interface (HTML, CSS, JavaScript, etc).
The Inter-Planetary File System (IPFS) is a decentralized content-addressable storage system that distributes stored objects among peers in a P2P network. "Content Addressable" means that each piece of content (file) is hashed and the hash is used to identify that file. You can then retrieve any file from any IPFS node, by requesting it by its hash.
IPFS aims to replace HTTP as the protocol of choice for delivery of web applications. Instead of storing a web application on a single server, the files are stored on IPFS and can be retrieved from any IPFS node.
More information about IPFS can be found at: https://ipfs.io
Swarm is another content-addressable P2P storage system, similar to IPFS. Swarm is built by the Ethereum Foundation, as part of the Go-Ethereum suite of tools. Like IPFS, Swarm allows you to store files that get disseminated and replicated by Swarm nodes. You can access any Swarm file by referring to it by a hash. Swarm allows you to access a web site from a decentralized P2P system, instead of a central web server.
The home page for Swarm is itself stored on Swarm and accessible on your Swarm node or a gateway: http://swarm-gateways.net/bzz:/theswarm.eth/
Another major component of any application is inter-process communication. That means being able to exchange messages between applications, between different instances of the application, or between users of the application. Traditionally, this is achieved by reliance on a centralized server.
There are a variety of decentralized alternatives to a server-based protocols, offering messaging over a P2P network. The most notable P2P messaging protocol for DApps is Whisper, which is part of the Ethereum Foundation’s Go-Ethereum suite of tools. More information about Whisper can be found here: https://github.com/ethereum/wiki/wiki/Whisper
In this section we will start building an example DApp, to explore the various decentralization tools. Our DApp will implement a decentralized auction.
The Auction DApp allows a user to register a "deed" token, which represents some unique asset, such as a house, a car, a trademark registration, etc. Once a token has been registered, the ownership of the token is transferred to the Auction DApp, allowing it to be listed for sale. The Auction DApp lists each of the registered tokens, allowing other users to place bids. During the auction, users can join a chat room, created specifically for each auction. Once an auction is finalized, the deed token ownership is transferred to the winner of the auction.
The overall auction process can be seen in here:
The main components of our Auction DApp are:
-
A smart contract implementing ERC721 non-fungible "deed" tokens (DeedRepository).
-
A smart contract implementing an Auction (AuctionRepository) to sell the deeds.
-
A web front-end using the Vue/Vuetify Javascript framework.
-
The web3.js library to connect to Ethereum chains (via MetaMask or other providers).
-
A Swarm client, to store resources such as images on Swarm.
-
A Whisper client, to create per-auction chat rooms for all participants
You can find the source code for the auction DApp in the book’s repository: https://github.com/ethereumbook/ethereumbook/tree/develop/code/auction_dapp
Our Auction DApp example is supported by two smart contracts that we need to deploy on an Ethereum blockchain in order to support the application: AuctionRepository and DeedRepository.
Let’s start by looking at DeedRepository. This contract is an ERC-721 compatible "non-fungible token" (See [erc721]). Here’s the source code for that contract:
link:code/auction_dapp/backend/contracts/DeedRepository.sol[role=include]
As you can see, the DeedRepository contract is a straightforward implementation of an ERC721 compatible token.
Our Auction DApp uses the DeedRepository contract to issue and track tokens for each auction. The auction itself is orchestrated by the AuctionRepository contract, which can be found here:
The AuctionRepository contract is too long to include here in full, but here is the main definition of the contract and data structures:
contract AuctionRepository {
// Array with all auctions
Auction[] public auctions;
// Mapping from auction index to user bids
mapping(uint256 => Bid[]) public auctionBids;
// Mapping from owner to a list of owned auctions
mapping(address => uint[]) public auctionOwner;
// Bid struct to hold bidder and amount
struct Bid {
address from;
uint256 amount;
}
// Auction struct which holds all the required info
struct Auction {
string name;
uint256 blockDeadline;
uint256 startPrice;
string metadata;
uint256 deedId;
address deedRepositoryAddress;
address owner;
bool active;
bool finalized;
}
The AuctionRepository contract manages all auctions with the following functions:
getCount() getBidsCount(uint _auctionId) getAuctionsOf(address _owner) getCurrentBid(uint _auctionId) getAuctionsCountOfOwner(address _owner) getAuctionById(uint _auctionId) createAuction(address _deedRepositoryAddress, uint256 _deedId, string _auctionTitle, string _metadata, uint256 _startPrice, uint _blockDeadline) approveAndTransfer(address _from, address _to, address _deedRepositoryAddress, uint256 _deedId) cancelAuction(uint _auctionId) finalizeAuction(uint _auctionId) bidOnAuction(uint _auctionId)
We can deploy these contracts to the Ethereum blockchain of our choice (e.g. Ropsten), using truffle in the book’s repository:
cd code/auction_dapp/backend truffle init truffle compile truffle migrate --network ropsten
Once the Auction DApp contracts are deployed, you can interact with them using your favorite Javascript console and web3.js, or another web3 library. However, most users will need an easy-to-use interface. Our Auction DApp user interface is built using the Vue2/Vuetify Javascript framework from Google.
You can find the user interface code in the code/auction_dapp/frontend folder in the book’s repository. The directory has the following structure and contents:
frontend/ |-- build | |-- build.js | |-- check-versions.js | |-- logo.png | |-- utils.js | |-- vue-loader.conf.js | |-- webpack.base.conf.js | |-- webpack.dev.conf.js | `-- webpack.prod.conf.js |-- config | |-- dev.env.js | |-- index.js | `-- prod.env.js |-- index.html |-- package.json |-- package-lock.json |-- README.md |-- src | |-- App.vue | |-- components | | |-- Auction.vue | | `-- Home.vue | |-- config.js | |-- contracts | | |-- AuctionRepository.json | | `-- DeedRepository.json | |-- main.js | |-- models | | |-- AuctionRepository.js | | |-- ChatRoom.js | | `-- DeedRepository.js | `-- router | `-- index.js
Once you have deployed the contracts, edit the front-end configuration in frontend/src/config.js and enter the address of the DeedRepository and AuctionRepository contracts, as deployed. The front-end application also needs access to an Ethereum node offering a JSON-RPC and websockets interface. Once you’ve configured the front-end, launch it with a web server on your local machine:
npm install npm run dev
The Auction DApp front-end will launch and will be accessible via any web browser at:
If all goes well, you should see the Auction DApp running in your web browser: