“I have always favoured decentralising power online. As a result, no organization can easily gain control. I don’t believe in big central organizations, it’s nature.” — Bob Tayor, founder of ARPANET

This article was originally published by the HT front-end team.Ht.askingdata.com/article/5af…

The “three o ‘clock Blockchain Group” at the beginning of this year completely aroused the blockchain wave dominated by cryptocurrency, and the capital drive deepened people’s enthusiasm for blockchain technology. However, as the wider application of blockchain 3.0 era comes, how to land the technology is also the first hurdle to be solved in the initial stage.

So let’s try out how to build a smart contract application (Dapp) on Ethereum today, and develop a normal app login so that we can try it first.

Why use blockchain?

As a standard Web developer, one question you need to consider carefully before starting a new technology is: Would it be better to use blockchain based on your existing business?

To answer this question, you need to know what a blockchain is. What are the advantages? I’m not going to do it here, but it’s a pretty big topic, so if you don’t know, you can go here. Blockchain – Baidu Encyclopedia, What is blockchain Technology and what might it be used for in the future?

So blockchain is essentially a decentralized database, but this database has no central server, data cannot be tampered with and data privacy can be protected to a certain extent. Sounds like revolutionary technology for today’s Internet. So for an application that involves data privacy and permanent security, this is really a good fit.

Now, in finance, healthcare, traceability, social and other fields, many companies are beginning to test the waters of a wider range of applications. And only rely on coin coin speculation, after all, this is a kind of opportunistic behavior.

Essential foundation for ethereum entry

The next step is to build an Ethereum Web3JS project from scratch. Before you can start reading, you will need to be familiar with the front-end or back-end JavaScript syntax and be familiar with blockchain ideas and principles. It is even better to know solidity syntax as we will be using it, a language very similar to JS.

In order to facilitate you to quickly understand, the following information is provided for reference:

  1. Official website of Ethereum.
  2. The Official Sails File is a backend NodeJS framework.
  3. We3.js document version 1.0 front-end framework on Ethereum to interact with contracts.
  4. Ethereum’s smart contract language, familiar with common syntax, similar to JavaScript syntax.

After understanding the above knowledge, you can start the DAPP construction journey, which will be explained from the following route:

  1. Build the Ethereum environment.
  2. Create the creation block.
  3. Simply mine and create an account.
  4. Use ethereum wallet to query account information.
  5. Write smart contracts.
  6. Web3.js interacts with contracts.
  7. Log in to register the business logic implementation.
  8. Postman interface test

The project code can be viewed at github.com/Elliottssu/…

1. Ethereum environment construction

If you already have an Ethereum environment, you can skip it. Let’s take the MAC system as an example, and Windows is pretty much the same.

Install Go-Ethereum through Homebrew

brew tap ethereum/ethereum

You can install the development branch by adding –devel (recommended) :

brew install ethereum --devel

Run the geth version command to check the version. If the version is correct, the installation succeeds.

Ii. New Trands Block

In the Bitcoin system, the genesis block is written into the source code, but in the case of Ethereum, the genesis block can be anything you like. You can also view this as a bug in the system. But consensus algorithms ensure that other people won’t be effective unless they’re included in your creation block.

The purpose of Trands block is to build a private chain. As the first block on the chain, if the node is directly run, the data of the public chain will be synchronized, and the data volume will be very large. If you want to get data from the same network, genesis has to do the same.

Create the genesis.json file as follows:

{
    "config": {},
    "nonce": "0x0000000000000042"."mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000"."difficulty": "0x100"."alloc": {},
    "coinbase": "0x0000000000000000000000000000000000000000"."timestamp": "0x00"."parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"."extraData": "0x00"."gasLimit": "0xffffffffffff"
}
Copy the code

It defines things like mining difficulty, amount of Ether, gas consumption limit, and so on.

Execute geth init genesis. Json in the current directory to initialize the Genesis block node.

At this point, the environment configuration aspect is complete. We can start the node on port 8545 with the following command:

geth --rpc --rpccorsdomain "*" --rpcapi "personal,web3,eth,net" console

Create accounts and mine

First we need to create the first account password 12345678, run:

personal.newAccount('12345678')

After you create an account, you can mine. Note that if you have multiple accounts, the mined Ether will go into the balance of the first account by default.

Miner.start () starts mining, and miner.stop() stops mining

4. Use ethereum wallet to query account information

As of now, we have successfully started the Ethereum node, and can use commands to create accounts and perform mining operations to acquire Ethereum coins. However, we may not be able to intuitively feel the change of account and balance on Ethereum through commands.

Accounts and balances are now managed through wallets provided by ethereum officials. Download from github.com/ethereum/mi…

Note: it is recommended to install V0.8.10, which can delete the deployed contract for easy debugging. The latest version removes the change function.

If there is a Trands block and it is a private chain, the Ethereum wallet will enable the private node by default, otherwise it will synchronize data on the public chain by default.

You can use your main account to transfer money to other accounts. You can also create a new account and check the balance of your account.

Write smart contracts for idity

First of all, what is a smart contract? The smart contract concept can be summarized as: a piece of code (smart contract), a computer program that runs on a ledger that can be copied and shared, can process information, receive, store, and send value. In layman’s terms, it’s code that can be executed on a blockchain, because ethereum’s old blockchain could only store transactions on Bitcoin and nothing else. The emergence of smart contracts, which can perform simple business logic on the chain, is also the key to the implementation of blockchain applications.

Now that we have the basics in place, let’s write the data increment and query logic in the Solidity language.

What a contract means in Solidity is a set of code (its functions) and data (its state) at a specific address on the Ethereum blockchain. Uint time; Declare a state variable of type uint (256 bit unsigned integer) called time. You can think of it as a location in the database that can be queried and changed by calling functions that manage the database code. In the case of Ethereum, it’s all about owning a contract. In this case, the functions set and GET can be used to change or extract the value of a variable.

1. Define data structures and variables

Here just do a simplest account system, define a user’s data structure including user name, user address and registration time.

The user list data structure is defined to store a mapping of user names -> user addresses.

//user.sol
// Define the user data structure
struct UserStruct {
    address userAddress;
    string username;
    uint time;
    uint index;
}

// Define the user list data structure
struct UserListStruct {
    address userAddress;
    uint index;
}

address[] public userAddresses; // All addresses set
string[] private usernames; // A collection of all user names
mapping(address= > UserStruct) private userStruct; // Account personal information

mapping(string= > UserListStruct) private userListStruct; // User name mapping address


Copy the code

address[] private userAddresses; This line declares a state variable of type ADDRESS that is not publicly accessible. The address type is a 160-bit value and does not allow any arithmetic operations. This type is suitable for storing the contract address or the key pair of an external person. If the keyword public allows you to access the current value of the state variable outside of the contract.

mapping(address => UserStruct) private userStruct; An address is mapped to a user data structure. This can be briefly understood as the values corresponding to an address.

2. Check whether the user name or address exists

//user.sol
// Check whether the user address exists
function isExitUserAddress(address _userAddress) public constant returns(bool isIndeed) {
    if (userAddresses.length == 0) return false;
    return (userAddresses[userStruct[_userAddress].index] == _userAddress);
}

// Check whether the user name exists
function isExitUsername(string _username) public constant returns(bool isIndeed) {
    if (usernames.length == 0) return false;
    return (keccak256(usernames[userListStruct[_username].index]) == keccak256(_username));
}
Copy the code

Here we determine whether the user name and address exist respectively by looking at whether the user name or address exists in the corresponding array.

Note that in JavaScript indexOf() is used to determine whether a value is used in an array, but in Solidity this function is not supported. There are two options: one is to loop through the collection to determine whether it exists, and the other is to add index index to each item of data when creating it.

Because the first method requires traversing the entire array, it is not efficient when the data volume is very large, so indexing is faster.

3. Create and query data

In the case of data inserts and queries, you are simply adding and reading data into an array collection.

//user.sol
// Find the address based on the user name
function findUserAddressByUsername(string _username) public constant returns (address userAddress) {
    require(isExitUsername(_username));
    return userListStruct[_username].userAddress;
}


// Create user information
function createUser(address _userAddress, string _username) public returns (uint index) {
    require(! isExitUserAddress(_userAddress));// If the address already exists, it cannot be created again

    userAddresses.push(_userAddress); // Address set push new address
    userStruct[_userAddress] = UserStruct(_userAddress, _username, now, userAddresses.length - 1);

    usernames.push(_username); // User name set push new user
    userListStruct[_username] = UserListStruct(_userAddress, usernames.length - 1); // Address set corresponding to the user

    return userAddresses.length - 1;
}


// Get user's personal information
function findUser(address _userAddress) public constant returns (address userAddresses, string username, uint time, uint index) {
    require(isExitUserAddress(_userAddress));
    return (
        userStruct[_userAddress].userAddress,
        userStruct[_userAddress].username,
        userStruct[_userAddress].time,
        userStruct[_userAddress].index); 
}
Copy the code

Of course, in addition to adding and querying, you can also modify and delete the corresponding array. The modification and deletion operations here are not really changing the data, because the data on the blockchain cannot be tampered with. Of course, it is not recommended to modify and delete data directly on the chain unless absolutely necessary.

6. Web3.js and contract interaction

Now that we have the smart contract written, we can read and add data through JS, but before that we need to deploy the contract we just wrote. A quick and convenient way to deploy contracts is in an Ethereum wallet.

After the deployment is complete, mining is required to succeed

When we’re done, we can find the contract we just deployed in the contract list.

Tips: After the first contract is deployed, exit should be executed if you want to push out, otherwise the contract will not be saved.

Now you can click in and write and read data. So how do you do that with code?

Take a look at the sails file directory in advance:

1. Install the truffle

Truffle can compile solidity smart contracts into.json configuration files that can be used to interact with web3.js.

NPM install -g truffle

Compile solidity Smart Contracts, truffle Compile

After execution, the compiled results are printed in the build directory.

2. Copy the ABI value in the compiled file

The purpose of compiling is to take the configuration parameters for the ABI properties and manually copy them into the NodeJS configuration file.

Ps: This is a bit silly, but the project’s official recommendation is that the contract is much easier to deploy and read.

3. Web3.js reads and creates contract content

Let’s look at how contracts are invoked on web3.js:

Reading with methods.mymethod.call calls the “constant” method and executes its smart contract method in EVM without sending any transactions. Note that the invocation does not change the smart contract state; Modify methods.mymethod. send to send the transaction to the smart contract and execute its method. Note that this can change the smart contract status.

Now wrap some web3.js classes that call smart contracts based on the content of ethereum contracts.

//Contract.js
const web3Util = require('./Web3Util.js')

class Contract {

    constructor() {}/ / user agreement

    /** * Check whether the user name exists */

    static isExitUsername(username, cb) {
        web3Util.contractUser.methods.isExitUsername(username).call()
            .then(result= > {
                cb(null, result)
            })
            .catch(err= > {
                cb(err.message)
            });
    }

    /** * Find the correct address */ based on the user name
    static findUserAddressByUsername(username, cb) {
        web3Util.contractUser.methods.findUserAddressByUsername(username).call()
            .then(result= > {
                cb(null, result)
            })
            .catch(err= > {
                cb(err.message)
            });
    }

    /** * Find user information */
    static findUser(userAddress, cb) {
        web3Util.contractUser.methods.findUser(userAddress).call()
            .then(result= > {
                cb(null, result)
            })
            .catch(err= > {
                cb(err.message)
            });
    }

    /** * Create user information */
    static createUser(userAddress, username, cb) {
        let options = {
            from: Web3Util.ACCOUNT_ADDRESS_MAIN, // Create account with primary account
            gas: 10000000 // Maximum gas value
        }
        web3Util.contractUser.methods.createUser(userAddress, username).send(options)
            .then(result= > {
                cb(null, result)
            })
            .catch(err= >{ cb(err.message) }); }}module.exports = Contract;
Copy the code

The file above defines some common constants in web3util.js, such as contract address, account address, etc. It is important to note that gas should be tipped when using.send() to create the content of the contract, but not when reading the content. This is mandatory for ethereum smart contracts, and you can read about how gas is consumed.

7. Login and register business logic implementation

So far we have successfully linked and interacted with JS and Solidity, so the next step is to implement login and register.

To log in is to see if you can unlock the user and then return the user’s personal information. To register is to call up the smart contract and write a record.

Unlock account (only unlocked to execute contract) method:

//Web3Util.js
/** * Unlock account * @param account Account name * @param password Password */
static unlockAccount(account, password, cb) {
    Web3.eth.personal.unlockAccount(account, password, 600)
        .then(result= > {
            cb(null, result)
        })
        .catch(err= > {
            cb(err.message)
        });
}
Copy the code

Login registration execution code:

//AccountController.js

module.exports = {
    // Check whether the user name exists
    isExitUsername: (req, res) = > {
        let username = req.query.username;
        if(! username)return res.json(Message.errMessage('User name cannot be empty'));
        Contract.isExitUsername(username, (err, result) => {
            Message.handleResult(res, err, result)
        })
    },

    // Login (user name or address login)
    login: (req, res) = > {
        let account = req.body.account
        let password = req.body.password;
        if(! account || ! password)return res.json(Message.errMessage('User name or password cannot be empty'));

        if (Web3.utils.isAddress(account)) { //account is address

            Web3Util.unlockAccount(account, password, (err, result) => {
                if (err) return res.json(Message.errMessage('Wrong username or password'));
                Contract.findUser(account, (err, result) => {
                    Message.handleResult(res, err, result)
                })
            })
        } else { //account is username

            Contract.findUserAddressByUsername(account, (err, address) => {
                if (err) return res.json(Message.errMessage('Wrong username or password'));
                Web3Util.unlockAccount(address, password, (err, result) => {
                    if (err) return res.json(Message.errMessage('Wrong username or password'));
                    Contract.findUser(address, (err, result) => {
                        Message.handleResult(res, err, result)
                    })
                })
            })

        }
    },

    /** * register an account and generate address in Ethereum. The username will be written in the contract */
    register: (req, res) = > {
        let username = req.body.username
        let password = req.body.password;
        if(! username || ! password)return res.json(Message.errMessage('User name or password cannot be empty'));
        async.waterfall([
            function (callback) { // Check whether the user name exists
                Contract.isExitUsername(username, (err, result) => {
                    if (result) return res.json(Message.errMessage('Username already exists'));
                    callback(null, result)
                })
            },
            function (result, callback) {  // Create user > Generate address
                Web3.eth.personal.newAccount(password).then(address= > {
                    callback(null, address)
                })
            },
            function (address, callback) {  // Unlock the master account and contract the registration information
                Web3Util.unlockAccount(Web3Util.ACCOUNT_ADDRESS_MAIN, Web3Util.ACCOUNT__PASSWORD_MAIN, (err, result) => {
                    if (err) return res.json(Message.errMessage(err));
                    Contract.createUser(address, username, (err, result) => {
                        if (err) return res.json(Message.errMessage(err));
                        callback(err, result)
                    })
                })
            },
        ], (err, result) => {
            Message.handleResult(res, err, result)
        })
    },

};


Copy the code

Postman interface test

Now that we have configured the router, we can use the interface debugging tool to test it. Here we use Postman to test it:

Note that before starting the test, you need to enable the Ethereum node and ensure that port 8545 is enabled: GETH — RPC — rPCCorsDomain “*” — RPCAPi “Personal,web3, ETH, NET” console

Since the registration needs to change the contract data, mining is needed to confirm the transaction, so in order to facilitate debugging, by the way, start mining: miner.start()

1. Set up an account

Since it is a contract transaction, the transaction details such as blocks, consumed gas, and so on are returned after registration. If the transaction fails, such as registering duplicate user names again, and intercepting in solidity, the transaction fails, the failure sign is that the gas returned is the maximum value you set.

This creates an Address on the chain, along with the corresponding user name and time of registration.

2. Login account (address and user name are supported)

subsequent

Now that we can interact with smart contracts through interfaces, we can add a little front-end page, which can be regarded as a normal APP, but the database is blockchain, isn’t it cool?

Of course, only a small amount of data can be stored on a blockchain. If you want to store videos or pictures, you can use IPFS, a permanent, decentralized method of storing and sharing files, which is a distributed protocol for addressable content, versioning, peer-to-peer hypermedia. With block chain can achieve richer functions.

The current disadvantage is that it is relatively slow to read and store transaction data, which is part of the reason why Dapp applications cannot be carried out on a large scale at present. However, this will not hinder the development of blockchain technology, because it deals with production relations, and its idea lies in decentralization to prevent the abuse of central organizations.

At the time I was composing this article, Facebook founder Mark Zuckerberg was being grilled at a hearing about a data leak scandal that involved using millions of users’ data to interfere in the presidential election. Once user privacy data is breached or abused or recommended by commercial analysis, the consequences are also very terrible, which is also the drawback brought by the globalization of the Internet today.

So, if you want blockchain to solve this problem, how far do you need to go?