JURIX 2015: Setting Up an Ethereum Testnet

In conjunction with the tutorial I will be giving today at JURIX 2015, I whipped up this guide on using Geth to set up (and interact with) an Ethereum testnet. This owes a big debt to this amazing tutorial by Ade Duke as well as Eva Shon and the folks at ConsenSys. Thank you so much!

OK, here goes nothing!:

First Make Sure You Have Geth Installed


To install Geth, open Terminal (sorry, this tutorial is Mac-only) and do: bash <(curl https://install-geth.ethereum.org -L)

If you get an error, try one or all of these and then try that line above again:

  1. Install X-Code: xcode-select --install
  2. Install git: brew install git
  3. Install homebrew: ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

To see if it has worked, do: geth

Now Let’s Set Up Our Testnet

In some directory of yours, create a folder called Ethereum and, inside that, a folder called testnet. Now inside that last folder, create a document called genesisblock.json. Paste the following text and nothing else in there:

{
    "nonce": "0xlookatmeimanonce",
    "timestamp": "0x00",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "extraData": "0x00",
    "gasLimit": "0x08000000",
    "difficulty": "0x0400",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "coinbase": "0x3333333333333333333333333333333333333333",
    "alloc": {
    }
}

This is going to be the genesis block (block 0) of your testnet. Make sure that everyone you are going to want to be on your testnet has the exact same genesis block, verbatim (and stashed in a similar folder structure). Then, open (or return to) Geth in the command line and enter this, below, inserting your path names, to instantiate your testnet:

geth --genesis %PATH%/Ethereum/testnet/genesisblock.json --datadir %SAME_PATH%/Ethereum/stateinfo --networkid 1234 --nodiscover console

Just to break this down a little, the first flag tells geth the path to our genesis block. The second flag tells Geth the directory that we will use to store the blockchain data that will precipidate from creating the testnet. The penultimate flag tells geth our networkid number. (You can pick any number you want here, but choose below 65000, because the testnet will map onto a port and that is likely the limit of ports on your machine). The last flag tells that we don’t want our testnet to be open to the public. And the last argument indicates that we want to use this geth window as the Javascript console going forward.

After you do that, one helpful thing to do is run: admin.verbosity(6). That increases the level of feedback from the console. Sometimes, it gets to be a little too much and you’ll want to turn it off. Do that by entering: admin.verbosity(0)

Next, Add a Peer to Your Testnet

Again, make sure they do all of the above, the same as you. Then ask them to run this in their console: admin.nodeInfo

Now find the NodeURL part of the response. It should look like this: NodeUrl: "enode://b5ab86648b621609405eccc900be66b4b367331537c3bbe3317b80be741aedb0f147ed73d023ef18b690c29b64a6fb36d6588e6bd0e0b2efbdf3a4a282a5accc@[::]:30303?discport=0"

Now have them open another Terminal window and run ifconfig.

Have them copy the left-most inet address listed under en0 (the computer’s wifi interface). Have them replace this part of their NodeURL (including the brackets) with that inet address: [::]

It should look something like this:

"enode://dd191dcb0d5bdc9294b727d2b5a62f88df315b8c84b6883a8cc1eef239d21a5c13a5e3951978588370f5d6cfb175309f8407b32c3bf3196fc99329fa59ebd5e2@193.168.146.148:30303?discport=0"

Have them email or message you the resulting string, in quotes.

Now, in your Geth Javascript console (which should still be running) do admin.addPeer() – and plug in that above stuff in the quotes that your invitee sent you as your argument. To check that it worked: admin.peers

Now both do this: set up account inside your new testnet with personal.newAccount("mypasswd”).

It will return an address. You have an account on the testnet! Tell your invitee to save thir account number…we’ll need it later.

Try Sending Ether Over Your Testnet

First mine a little bit so that you can try out transaction (remember, you need gas for that, which means you need ether. So do: miner.start(8)

After about a minute, do: miner.stop()

To make sure you earned some ether, check the balance with: eth.getBalance(eth.coinbase).toNumber();

Copy down that address so we’ll be able to see if it receives the ether we send it. Now you must unlock the account to be able to spend the ether: personal.unlockAccount(eth.coinbase)

Now can send a transaction. Just replace the Ethereum address below with your invitee’s: eth.sendTransaction({from:eth.coinbase, to: '0x33d983583f0bbdae923bf79773afe1022a0eb644', value: web3.toWei(.000000000001, "ether")})

Next one of you has to mine again to add the transaction to a block. (Remember, that’s how the blockchain works!) Repeat the mining directions from above. Their account balance should go up (it’s a very small amount of Wei that was sent, so hopefully it will be easy to see if it has shown up in their account). If the transaction fails, try sending more gas with the transaction by adjusting the last parameter above.

Ok, Now Let’s Try to Create a Contract

Let’s use the SimpleStorage contract from the Solidity Tutorial to prove this works.

Copy the code for the contract here or just copy this:

contract SimpleStorage {
    uint storedData;
    function set(uint x) {
        storedData = x;
    }
    function get() constant returns (uint retVal) {
        return storedData;
    }
}

Copy and paste it into the online Solidity Compiler.

On the right side of the Compliler, you’ll see it has converted to web3 code. Copy just that web3 code. Save the web3 code as a .js file in same directory you run geth from. Then do this:loadScript('SimpleStorage.js');

Then have someone mine — either you or a companion on the testnet. Once mining starts, you’ll see transaction get processed and it should spit back a transaction ID. This, of course, means you mined a new block that included that transaction.

To make sure that it went through, type this into the console and it should return you the contract address: simplestorage

You might also try doing:

  1. simplestorageContract.abi — this will show you that the EVM has understood the contract’s functions and variables. When you see some labelled “constant,” that means it is free to interact with those functions, as they are only read only.
  2. simplestorage.address will also tell you the address.

If another person on your testnet wants to interact with the contract, they have to bring it into their console. To let them do, get the abi and the address by using those calls above, and then have that other person run: var simpleStorageOnBlockchain = eth.contract(%ABI_FROM_ABOVE%).at(%ADDRESS_FROM_ABOVE%);

Now that you can both interact with the contract, call the get method and see if the contract is holding an integer: simplestorage.get()

You should get back 0, the default value. Now let’s try to use the set method to pass a different integer in using: simplestorage.set(5,{from: eth.accounts[0], gas: 3000000})

Just to break this down, the first parameter is our argument and the second is the details of the transaction: the send and the gas amount sent in. eth.accounts[0], by the way, is a way to refer to the present account. Try to see what the contract holds again using the get method. Try: simplestorage.get()

You should get a 5. If you do, you just set up your first contract on a testnet blockchain! Whoot whoot!