×
Community Blog Getting Started with Ethereum Smart Contract Development

Getting Started with Ethereum Smart Contract Development

In this tutorial, you will get you will get a taste with developing with Ethereum Smart Contract.

An Ethereum contract consists of a code string and data on a specific account address of an Ethereum blockchain. Contract accounts not only can communicate with each other, but they can also execute almost of all of the Turing Complete computations available now. The contract code on an Ethereum blockchain is in a specific binary form, which is known as Ethereum Virtual Machine (EVM) binary code.

However, contracts are usually developed and written in some sort of advanced language, which is translated into binary code and uploaded to the blockchain. Existing Ethereum advanced development languages are JavaScript-like Solidity, Python-like Serpent, and Lisp-like LLL. This article will be using the first of these language, Solidity.

Solidity is an object-oriented advanced Ethereum development language. Influenced by C++, Python, and JavaScript, it supports static types, inheritance, class libraries, and complex custom features. A typical contract development process includes writing, compiling, publishing, and calling.

The Eth Command Line Tool Geth

The Ethereum network command line client provides the Go-based Geth and C++-based Eth command-line tools. Geth is mainly used for Web development and Dapp front-end construction, while Eth is mainly used for GPU mining. But besides these differences, the two functions are almost identical. This article will use Geth because it is both easy-to-use and relatively widely used.

To begin this tutorial, let's first install and start ethereum. You can install ethereum using with the following actions and using brew with the following command.

brew tap ethereum/ethereum
brew install ethereum

Then, run ethereum with following command:

geth console

By default, you will be connected to the Ethereum main network. The main network is slow and expensive, and transfers, the deployment of contracts, and call to contracts consume Ether (ETH), so it cannot be directly used for development. As a result, you'll want to build a private test network. A private test network needs to be set up, of which you are the only member. You are responsible for all the tasks, such as block generation, transaction verification, and smart contract execution. This helps to develop contracts at a low cost, simply and quickly.

You can use genesis.json to initialize the Genesis block, and set the datadir Directory:

geth --datadir ~/.ethereum_private init ~/dev/genesis.json

The genesis.json is as follows:

{
  "config": {
    "chainId": 12345,
    "homesteadBlock": 0,
    "eip155Block": 0,
    "eip158Block": 0
  },
  "nonce": "0x0000000000000033",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "gasLimit": "0xffffffff",
  "difficulty": "0x100",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}

In the following, the chainid and gaslimit configurations are specified. The initialization submission result is as follows:

INFO [02-13|16:08:23] Maximum peer count                       ETH=25 LES=0 total=25
INFO [02-13|16:08:23] Allocated cache and file handles         database=/Users/shanyao/.ethereum_private/geth/chaindata cache=16 handles=16
INFO [02-13|16:08:23] Writing custom genesis block
INFO [02-13|16:08:23] Persisted trie from memory database      nodes=0 size=0.00B time=7.737µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-13|16:08:23] Successfully wrote genesis state         database=chaindata                                       hash=76bc36…4efba1
INFO [02-13|16:08:23] Allocated cache and file handles         database=/Users/shanyao/.ethereum_private/geth/lightchaindata cache=16 handles=16
INFO [02-13|16:08:23] Writing custom genesis block
INFO [02-13|16:08:23] Persisted trie from memory database      nodes=0 size=0.00B time=1.16µs  gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-13|16:08:23] Successfully wrote genesis state         database=lightchaindata                                       hash=76bc36…4efba1

Next, start the private network with the datadir, and bind a console through the inter-process communication path (ipc path), as shown below:

geth --fast --cache 512 --ipcpath ~/Library/Ethereum/geth.ipc --networkid 12345 --datadir ~/.ethereum_private  console 

The result is as follows:

INFO [02-13|16:09:20] Maximum peer count                       ETH=25 LES=0 total=25
INFO [02-13|16:09:20] Starting peer-to-peer node               instance=Geth/v1.8.2-stable/darwin-amd64/go1.10
INFO [02-13|16:09:20] Allocated cache and file handles         database=/Users/shanyao/.ethereum_private/geth/chaindata cache=384 handles=1024
WARN [02-13|16:09:20] Upgrading database to use lookup entries
INFO [02-13|16:09:20] Database deduplication successful        deduped=0
INFO [02-13|16:09:20] Initialised chain configuration          config="{ChainID: 123456 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Constantinople: <nil> Engine: unknown}"
INFO [02-13|16:09:20] Disk storage enabled for ethash caches   dir=/Users/shanyao/.ethereum_private/geth/ethash count=3
INFO [02-13|16:09:20] Disk storage enabled for ethash DAGs     dir=/Users/shanyao/.ethash                       count=2
INFO [02-13|16:09:20] Initialising Ethereum protocol           versions="[63 62]" network=12345
INFO [02-13|16:09:20] Loaded most recent local header          number=0 hash=76bc36…4efba1 td=256
INFO [02-13|16:09:20] Loaded most recent local full block      number=0 hash=76bc36…4efba1 td=256
INFO [02-13|16:09:20] Loaded most recent local fast block      number=0 hash=76bc36…4efba1 td=256
INFO [02-13|16:09:20] Regenerated local transaction journal    transactions=0 accounts=0
INFO [02-13|16:09:20] Starting P2P networking
INFO [02-13|16:09:22] UDP listener up                          self=enode://42b0eec728cad819259d9685807bf78105450b6b28cd39d70417aa65ffebd3ac744b63d0446174bc657c9a42de2f0f9bc0f9589998c960177b844d5a962d8da9@[::]:30303
INFO [02-13|16:09:22] RLPx listener up                         self=enode://42b0eec728cad819259d9685807bf78105450b6b28cd39d70417aa65ffebd3ac744b63d0446174bc657c9a42de2f0f9bc0f9589998c960177b844d5a962d8da9@[::]:30303
INFO [02-13|16:09:22] IPC endpoint opened                      url=/Users/shanyao/Library/Ethereum/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.2-stable/darwin-amd64/go1.10
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

>

Now, the local private Ethereum network has been started. Now that that's been done, you can view the network. To do so, enter admin to view the network information, as shown below:


> admin
{
  datadir: "/Users/shanyao/.ethereum_private",
  nodeInfo: {
    enode: "enode://42b0eec728cad819259d9685807bf78105450b6b28cd39d70417aa65ffebd3ac744b63d0446174bc657c9a42de2f0f9bc0f9589998c960177b844d5a962d8da9@[::]:30303",
    id: "42b0eec728cad819259d9685807bf78105450b6b28cd39d70417aa65ffebd3ac744b63d0446174bc657c9a42de2f0f9bc0f9589998c960177b844d5a962d8da9",
    ip: "::",
    listenAddr: "[::]:30303",
    name: "Geth/v1.8.2-stable/darwin-amd64/go1.10",
    ports: {
      discovery: 30303,
      listener: 30303
    },
    protocols: {
      eth: {
        config: {...},
        difficulty: 256,
        genesis: "0x76bc36aeb54afba3cb6dc2a5d13818edabeb7f119f8bf61ee127854b624efba1",
        head: "0x76bc36aeb54afba3cb6dc2a5d13818edabeb7f119f8bf61ee127854b624efba1",
        network: 12345
      }
    }
  },
  peers: [],
  addPeer: function(),
  clearHistory: function(),
  exportChain: function(),
  getDatadir: function(callback),
  getNodeInfo: function(callback),
  getPeers: function(callback),
  importChain: function(),
  removePeer: function(),
  sleep: function github.com/ethereum/go-ethereum/console.(*bridge).Sleep-fm(),
  sleepBlocks: function github.com/ethereum/go-ethereum/console.(*bridge).SleepBlocks-fm(),
  startRPC: function(),
  startWS: function(),
  stopRPC: function(),
  stopWS: function()
}

Then, you can view your node URL, as follows:

> admin.nodeInfo.enode
"enode://42b0eec728cad819259d9685807bf78105450b6b28cd39d70417aa65ffebd3ac744b63d0446174bc657c9a42de2f0f9bc0f9589998c960177b844d5a962d8da9@[::]:30303"

Note: You need to enter web3 to view all commands and structures. The prefixes of these commands are web3, which means that the effect of entering admin is the same as that of entering web3.admin.

Next, you can create an account:

> personal.newAccount("pk1")
"0xfb6565558c9fb3ef0eb657d5540bcd2859824e7f"
> personal.newAccount("pk2")
"0x9652670122f63ea19398f93d088ccb458b16cbf7"

The primary key here is your account password, which you will need to remember and save somewhere as you cannot recover it once it is lost.

Next, you can view the account:

> eth.accounts
["0xfb6565558c9fb3ef0eb657d5540bcd2859824e7f", "0x9652670122f63ea19398f93d088ccb458b16cbf7"]
> eth.accounts[0]
"0xfb6565558c9fb3ef0eb657d5540bcd2859824e7f"

The first account created is usually called the primary account.

Now Check the balance:

> var primaryAccount = web3.eth.accounts[0]
undefined
> web3.eth.getBalance(primaryAccount)
0

As you can see from the results, the current balance of the account is 0. Let's start miner with the web3.miner.start() command, and dig for a while to earn some ETH:


> web3.miner.start()
INFO [02-13|16:29:24] Updated mining threads                   threads=0
INFO [02-13|16:29:24] Transaction pool price threshold updated price=18000000000
INFO [02-13|16:29:24] Starting mining operation
null
> INFO [02-13|16:29:24] Commit new mining work                   number=1 txs=0 uncles=0 elapsed=187.297µs
INFO [02-13|16:29:27] Successfully sealed new block            number=1 hash=f59c04…83a194
INFO [02-13|16:29:27] ? mined potential block                  number=1 hash=f59c04…83a194
INFO [02-13|16:29:27] Commit new mining work                   number=2 txs=0 uncles=0 elapsed=113.91µs
INFO [02-13|16:29:27] Successfully sealed new block            number=2 hash=09f545…b0230d
INFO [02-13|16:29:27] ? mined potential block                  number=2 hash=09f545…b0230d

After a while, open another window and stop mining:

ali-186590cc4a7f-2:ethereum shanyao$ geth attach
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.2-stable/darwin-amd64/go1.10
coinbase: 0xfb6565558c9fb3ef0eb657d5540bcd2859824e7f
at block: 99 (Wed, 13 Feb 2019 16:31:07 CST)
 datadir: /Users/shanyao/.ethereum_private
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

> web3.miner.stop()
true

Next, check the account balance again:

> web3.eth.getBalance(primaryAccount)
565000000000000000000

Create a Contract with the Command Line Tool

First, let's write. To create a contract with the command line tool, you'll want to first create a simple "hello world" contract. The code is as follows:

pragma solidity >=0.4.22 <0.6.0;

contract Mortal {
    /* Define variable owner of the type address */
    address owner;

    /* This constructor is executed at initialization and sets the owner of the contract */
    constructor() public { owner = msg.sender; }

    /* Function to recover the funds on the contract */
    function kill() public { if (msg.sender == owner) selfdestruct(msg.sender); }
}

contract Greeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;

    /* This runs when the contract is executed */
    constructor(string memory _greeting) public {
        greeting = _greeting;
    }

    /* Main function */
    function greet() public view returns (string memory) {
        return greeting;
    }
}

From the above we can see that two contracts, Greeter and Mortal, exist. Greeter inherits from Mortal. In addition to the Kill function of Mortal, it has also added Greet function. It should be noted that the contract in Ethereum is immortal and uncontrolled by default. That is, once the contract is deployed on the blockchain, even the author of the contract no longer has the privilege to control the contract. The contract is defined by the author, but the execution of the contract and the services it provides are supported by the entire Ethereum network. As long as the entire network still exists, the contract will continue to exist and run. The contract will not disappear unless a self-destruction program is written and triggered.

The next step is to compile. Currently, the most convenient way to develop a contract is to use online IDE REMIX. After you paste in the code, it is automatically compiled as follows:

1

Pay attention to the ABI, ByteCode, and other key information in the Details of the compilation results on the right. The ABI (Application Binary Interface) is as follows:

[
  {
    "constant": false,
    "inputs": [],
    "name": "kill",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "greet",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "name": "_greeting",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "constructor"
  }
]

The next step is to deploy. Specifically, WEB3DEPLOY is the JS code of the contract to deploy, which is as follows:

var _greeting = "hello world!"; /* var of type string here */ ;
var greeterContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
var greeter = greeterContract.new(
   _greeting,
   {
     from: web3.eth.accounts[0], 
     data: '0x608060405234801561001057600080fd5b506040516103c73803806103c78339810180604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600190805190602001906100dc9291906100e3565b5050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610230806101976000396000f3fe608060405260043610610046576000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b51461004b578063cfae321714610062575b600080fd5b34801561005757600080fd5b506100606100f2565b005b34801561006e57600080fd5b50610077610162565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b757808201518184015260208101905061009c565b50505050905090810190601f1680156100e45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610160573373ffffffffffffffffffffffffffffffffffffffff16ff5b565b606060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fa5780601f106101cf576101008083540402835291602001916101fa565b820191906000526020600020905b8154815290600101906020018083116101dd57829003601f168201915b505050505090509056fea165627a7a7230582083829c23804682d77517133b1aba64edd8cb8cc98a0f9cd40fc419024eb92ce00029', 
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

Paste the code into the Geth window, and submit it to the private blockchain network. Before that, you need to unlock the account, as follows:

> personal.unlockAccount(web3.eth.accounts[0],"pk1")
true

Otherwise, the following error occurs: Error: authentication needed: password or unlock undefined. The result of deploying the contract is as follows:


INFO [02-13|17:15:47] Submitted contract creation              fullhash=0x5cafc176adea94dafee6ae1a6daa8b1ece894666ccac85f7858b16af5e15cdbe contract=0x579756a30442b508e2F6A0a4b4D1F4d871f9B906

This indicates that the contract creation transaction has been submitted, but the blockchain has not yet been mined at this time, so the transaction has not been packaged into the blockchain, and the entire blockchain network cannot be seen. Here, you must manually start mining again (mining is carried out continuously on the main network without stopping. The private test network here only has one node. For a clear demonstration, you need to manually start or stop mining each time). It can be seen in a few seconds:

Contract mined! address: 0x579756a30442b508e2f6a0a4b4d1f4d871f9b906 transactionHash: 0x5cafc176adea94dafee6ae1a6daa8b1ece894666ccac85f7858b16af5e15cdbe

This indicates that the contract has been deployed to the blockchain network. You can check and confirm through eth.getCode(greeter.address):

> eth.getCode(greeter.address)
"0x608060405260043610610046576000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b51461004b578063cfae321714610062575b600080fd5b34801561005757600080fd5b506100606100f2565b005b34801561006e57600080fd5b50610077610162565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b757808201518184015260208101905061009c565b50505050905090810190601f1680156100e45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610160573373ffffffffffffffffffffffffffffffffffffffff16ff5b565b606060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fa5780601f106101cf576101008083540402835291602001916101fa565b820191906000526020600020905b8154815290600101906020018083116101dd57829003601f168201915b505050505090509056fea165627a7a7230582083829c23804682d77517133b1aba64edd8cb8cc98a0f9cd40fc419024eb92ce00029"

Now, the contract can be executed.

Now, the next step is to call, which you can do as follows:

> greeter.greet();
"hello world!"

This call process does not change the blockchain state, so it returns immediately and does not consume gas.

The last step is to clean up. The contract code will be permanently stored on the blockchain unless it is self-destroyed. Therefore, abandoned contracts need to be destroyed, which requires sending transactions to the blockchain and paying for execution. For example:

> personal.unlockAccount(web3.eth.accounts[0],"pk1")
true
> greeter.kill.sendTransaction({from:eth.accounts[0]})
INFO [02-13|19:43:17] Submitted transaction                    fullhash=0xd66e3f444948f6bc7dfbfda1fb680c29c8173b061212d2457ef5553c71e8600c recipient=0x579756a30442b508e2F6A0a4b4D1F4d871f9B906
"0xd66e3f444948f6bc7dfbfda1fb680c29c8173b061212d2457ef5553c71e8600c"

View the contract code again, as shown below:


> eth.getCode(greeter.address)
"0x"

With that finished, the contract code has been cleared.

Summary

Through learning about the general process of Ethereum contract development in this blog, you now have a understanding of the general process of Ethereum contracts, and share a basic understanding. For more in-depth tutorials, see Ethereum official documentation.

References

  1. Building a smart contract using the command line
  2. Command line tools for the Ethereum Network
  3. ETH docs (contracts)
  4. Solidity docs
0 0 0
Share on

Wei Kuo

3 posts | 1 followers

You may also like

Comments

Wei Kuo

3 posts | 1 followers

Related Products

  • LedgerDB

    A ledger database that provides powerful data audit capabilities.

    Learn More
  • Blockchain as a Service

    BaaS provides an enterprise-level platform service based on leading blockchain technologies, which helps you build a trusted cloud infrastructure.

    Learn More
  • ZOLOZ Smart AML

    Comprehensive, Intelligent Detecting, Big Data-Driven Anti Money Laundering (AML) Solution

    Learn More
  • Function Compute

    Alibaba Cloud Function Compute is a fully-managed event-driven compute service. It allows you to focus on writing and uploading code without the need to manage infrastructure such as servers.

    Learn More