Hello World! Revisiting the Ethereum Greeter tutorial for the summer of '17

in #ethereum7 years ago (edited)

Hello World.

Such was the amazement with which I first saw an HTML page render in Internet Explorer, that I couldn't resist typing these exact same words on the first "web page" I built. Ethereum is what the Internet was back then because in both cases the possibilities are endless while, at the same time, even the smallest of challenges you overcome feels like a personal triumph of sorts. 

The Greeter example is a good place to start if you are looking to get acquainted with Ethereum's cli tools and the engineering side of ÐApp development, but unfortunately no documentation can withstand the pace of development the Ethereum community offers so the tutorial in ethereum.org is in need of an update.

Getting down to business, this tutorial will assume that you are comfortable using the command line in both Linux and Geth or you can get up to speed quickly and, importantly, you have some Ether in your account. For clarity purposes, my development environment has the following setup:

solc Version: 0.4.11+commit.68ef5810.Linux.g++ 

geth Version: 1.6.7-stable-ab5646c5

evm Version: 1.6.7-stable-ab5646c5

Chain Version: Homestead 


In your favourite text editor, create the file greeter.sol as such:

pragma solidity ^0.4.11;

contract Greeter {

    /* Define variable owner of the type address */

    address owner;

    /* Define variable greeting of the type string */

    string greeting;

    /* A modifier acts as a filter on other functions */

    modifier onlyOwner() { 

        require (owner == msg.sender); 

        _; 

    }

    /* Constructor sets the owner of the contract and stores a greeting string given on deployment*/

    function Greeter(string _greeting) { 

        owner = msg.sender; 

        greeting = _greeting;

    }

    /* Main function */

    function greet() constant returns (string) { 

        return greeting; 

    }

    /* This function allows the owner to set a new greeting string */

    function setGreeting(string _greeting) { 

        greeting = _greeting; 

    }

    /* This function destroys the contract instance and returns its funds to the owner. Notice how the modifier acts a sort of access control on this function */

    function kill() onlyOwner { 

        selfdestruct(owner); 

    }

}

In this version of the greeter tutorial, we will be able to set a new greeting string after deployment and retain the ownership and mortality properties of the original tutorial. I trust the inline comments are helpful but comments and questions are welcomed!

Now we will need to compile the code and since Geth no longer supports compilation function we will use the solc  compiler itself. In your favourite shell:

$ solc --bin --abi greeter.sol -o build


If successful, this command will create both the binary and the  application binary interface (ABI) for the greeter contract and output it to a `build` directory. 

Confirm you have both ./build/greeter.abi and ./build/greeter.bin files. 

cat ./build/greeter.abi 

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

And...

$ cat ./build/creeter.bin 

0x6060604052341561000c57fe5b6040516104d63803806104d6833981016040528080518201919050505b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019080519060200190610080929190610088565b505b5061012d565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100c957805160ff19168380011785556100f7565b828001600101855582156100f7579182015b828111156100f65782518255916020019190600101906100db565b5b5090506101049190610108565b5090565b61012a91905b8082111561012657600081600090555060010161010e565b5090565b90565b61039a8061013c6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063a413686214610063578063cfae3217146100bd575bfe5b341561005957fe5b610061610156565b005b341561006b57fe5b6100bb600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919050506101f1565b005b34156100c557fe5b6100cd61020c565b604051808060200182810382528381815181526020019150805190602001908083836000831461011c575b80518252602083111561011c576020820191506020810190506020830392506100f8565b505050905090810190601f1680156101485780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff16600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156101b35760006000fd5b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b80600190805190602001906102079291906102b5565b505b50565b610214610335565b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102aa5780601f1061027f576101008083540402835291602001916102aa565b820191906000526020600020905b81548152906001019060200180831161028d57829003601f168201915b505050505090505b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106102f657805160ff1916838001178555610324565b82800160010185558215610324579182015b82811115610323578251825591602001919060010190610308565b5b5090506103319190610349565b5090565b602060405190810160405280600081525090565b61036b91905b8082111561036757600081600090555060010161034f565b5090565b905600a165627a7a7230582058af898b41d2be593e37def436ccefea8f348476d6f32c1afc1c0d3a3aa1beb50029


Now, we'll create a deployment script. Using your editor, create a file deployGreeter.js as such:

var _greeting = "Hello World";

var greeterContract = web3.eth.contract(...contents of your Greeter.abi as a single line of text... use mine above if needed...);

var greeter = greeterContract.new(

   _greeting,

   {

     from: web3.eth.accounts[0], 

     data: '...contents of your Greeter.bin as a single line of text... use mine above if needed...', 

     gas: '4700000'

   }, function (e, contract){

    console.log(e, contract);

    if (typeof contract.address !== 'undefined') {

         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);

    }

 })


Now attach a geth console to your favourite TESTNET and type the following:

> personal.unlockAccount(eth.accounts[0])

> loadScript("deployGreeter.js")


Once the contract has been mined, you will receive a message in your Geth console similar to:

Contract mined! address: 0x5e0271f2e17730b7719fa570dc5fc13bfa3a6183 transactionHash: 0x249fac28de5d0a2f155f6f4f76c2fd835d599b9261fd3dfb44648853b6e8cb38


Now we can interact with our Greeter bot. The greet() function is a "read only" command since we've specified it as constant in our greeter.sol, so it should return "Hello World" pretty quickly as it doesn't require code to propagate through the network channel at all.

> greeter.greet()


We can also change the greeting message at will. Actually anyone can, as long as they know your contract address and have the respective ABI. In your geth type:

> greeter.setGreeting("Hello Steemit!", {from:eth.accounts[0]})


This last function effectively changes the state of your contract and as such it will be propagated through all of the network.

 If you are on a TESTNET with multiple nodes it may take a few seconds to execute but you will receive a transaction hash like "0x4171738b04b4eb25ad08b22fba46d728d6ec09669ddc823bd8be48e63a303ee2" that you can use to look at the transaction itself while you wait. In geth:

>eth.getTransaction("...your own transaction hash...")

{

  blockHash: "0x0a9a2a0371bd28de1537f9b61de18605291602d43c48bd78dd9a78a9bedae2cb",

  blockNumber: 352,

  from: "...your eth.accounts[0]...",

  gas: 90000,

  gasPrice: 100000000000,

  hash: "0x4171738b04b4eb25ad08b22fba46d728d6ec09669ddc823bd8be48e63a303ee2",

  input: "0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e48656c6c6f20537465656d697421000000000000000000000000000000000000",

  nonce: 267,

  r: "0x85f767dbc2fa6e4dbc3f956787165005d7fb520c2ac0bc18da4a6c562e7408be",

  s: "0x4216604b5772f7193d10bf4c24878563eca34179fcaefa25ce07ed662c7860ac",

  to: "...your Greeter contract address...",

  transactionIndex: 0,

  v: "0x78",

  value: 0

}


Notice the input value for now: 0xa41368620....0e48656c6c6f20537465656d6974210. I'll cover the function signature in another tutorial, but for the fun of it, type in geth: 

> web3.toAscii("0e48656c6c6f20537465656d697421")

"\x0eHello Steemit!"


Finally, our setGreeting transaction must be finished by now, let's check if that is the case by looking for the transaction receipt. In geth:

> eth.getTransactionReceipt("...your own transaction hash...")

{

  blockHash: "0x0a9a2a0371bd28de1537f9b61de18605291602d43c48bd78dd9a78a9bedae2cb",

  blockNumber: 352,

  contractAddress: null,

  cumulativeGasUsed: 33610,

  from: "...your eth.accounts[0]...",

  gasUsed: 33610,

  logs: [],

  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",

  root: "0xfdce1da8e1f91e24b2b4d3ac7479817ebf9e3f6b11279c21043347d780477247",

  to: "...your Greeter contract address...",

  transactionHash: "...your own transaction hash...",

  transactionIndex: 0

}


Repeatedly calling greeter.greet() until the new greeting string is returned also works... of course. 

Now let's have a look at the Greeter contract storage to make sure our greeting has been etched in stone  blockchain ethereum storage. In geth:

> var Address = greeter.address

> eth.getStorageAt(Address, 0)

 "0x000000000000000000000000...your eth.accounts[0]..."

> eth.getStorageAt(Address, 1)

"0x48656c6c6f20537465656d69742100000000000000000000000000000000001c"

> web3.toAscii("0x48656c6c6f20537465656d69742100000000000000000000000000000000001c")

"Hello Steemit!\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"


How about that? Your own personal Greeter bot is now unstoppable!