Introduction to Ethereum - Part 1


Bhaskar S *UPDATED*10/16/2022


Overview

In the article Introduction to Blockchain, we introduced the concept of Blockchain at a very high-level.

In this article, we introduced Ethereum, an open-source, decentralized, distributed, public, blockchain-based computing platform.

Ethereum provides support for:

In this article, we will setup a private Ethereum blockchain network consisting of a single node to demonstrate the basic capabilities of Ethereum.

Installation

The installation will be on a Ubuntu 22.04 LTS based Linux desktop.

We will assume the logged in user is polarsparc with the home directory located at /home/polarsparc.

Ensure Docker is installed and setup. Else, refer to the article Introduction to Docker.

We will setup a directory structure by executing the following commands from the users home directory:

$ mkdir -p Ethereum/conf

$ mkdir -p Ethereum/data/test

Now, change the current working directory to the directory /home/polarsparc/Ethereum.

For our exploration, we will be downloading and using the official docker image ethereum/client-go:alltools-v1.10.25 for Ethereum Go Client.

To pull and download the docker image for Ethereum Go Client, execute the following command:

docker pull ethereum/client-go:alltools-v1.10.25

The following should be the typical output:

Output.1

alltools-v1.10.25: Pulling from ethereum/client-go
213ec9aee27d: Pull complete 
2963a9ae9217: Pull complete 
811f758345ec: Pull complete 
Digest: sha256:22a9874c0cf02914693023ec5fe5fb50a9861d13fd213ffa6492302454484554
Status: Downloaded newer image for ethereum/client-go:alltools-v1.10.25
docker.io/ethereum/client-go:alltools-v1.10.25

To check everything was ok with the Ethereum Go Client docker image, execute the following command:

$ docker run --rm --name geth ethereum/client-go:alltools-v1.10.25 geth version

The following would be the typical output:

Output.2

Geth
Version: 1.10.25-stable
Git Commit: 69568c554880b3567bace64f8848ff1be27d084d
Architecture: amd64
Go Version: go1.18.6
Operating System: linux
GOPATH=
GOROOT=go

Hands-on with Ethereum

In order to interact with Ethereum, we will need some accounts. We will need atleast two accounts to perform transactions such as transferring ethers from one account to another.

Every account in Ethereum has associated with it some state, which is in the form of a balance. In other words, Ethereum is basically a state machine and transactions between any two accounts change their state (which is the balance in this case).

For our setup, we will start with 4 accounts. To create an account to represent the bank, execute the following command:

$ docker run -it --rm --name geth -u $(id -u $USER):$(id -g $USER) -v $HOME/Ethereum:/root ethereum/client-go:alltools-v1.10.25 geth --datadir /root/data/test account new

As part of the account creation process, the command will prompt for a password. Type (and re-enter) the secret phrase as bank. The following would be the typical output:

Output.3

INFO [10-16|16:15:03.751] Maximum peer count                       ETH=50 LES=0 total=50
INFO [10-16|16:15:03.752] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: bank
Repeat password: bank

Your new key was generated

Public address of the key:   0x38081d2aE8F6Fa8Eb5Bf350a7D94dd7B965c8B40
Path of the secret key file: /root/data/test/keystore/UTC--2022-10-16T16-15-13.065074013Z--38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!

The following is the repetition of the above command to create the remaining 3 accounts for our setup.

Account #2 (to represent the buyer) with the password buyer:

$ docker run -it --rm --name geth -u $(id -u $USER):$(id -g $USER) -v $HOME/Ethereum:/root ethereum/client-go:alltools-v1.10.25 geth --datadir /root/data/test account new

Account #2 output:

Output.4

INFO [10-16|16:15:48.705] Maximum peer count                       ETH=50 LES=0 total=50
INFO [10-16|16:15:48.706] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: buyer
Repeat password: buyer

Your new key was generated

Public address of the key:   0xC519C4be7D978cD3AB6810136878bEA3b7150009
Path of the secret key file: /root/data/test/keystore/UTC--2022-10-16T16-15-54.177670500Z--c519c4be7d978cd3ab6810136878bea3b7150009

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!

Account #3 (to represent the dealer) with the password dealer:

$ docker run -it --rm --name geth -u $(id -u $USER):$(id -g $USER) -v $HOME/Ethereum:/root ethereum/client-go:alltools-v1.10.25 geth --datadir /root/data/test account new

Account #3 output:

Output.5

INFO [10-16|16:16:15.845] Maximum peer count                       ETH=50 LES=0 total=50
INFO [10-16|16:16:15.845] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: dealer
Repeat password: dealer

Your new key was generated

Public address of the key:   0x83d82f2Ebb88F14a885Bb2c8869458465dB6F662
Path of the secret key file: /root/data/test/keystore/UTC--2022-10-16T16-16-21.129917030Z--83d82f2ebb88f14a885bb2c8869458465db6f662

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!

Account #4 (to represent the dmv) with the password dmv:

$ docker run -it --rm --name geth -u $(id -u $USER):$(id -g $USER) -v $HOME/Ethereum:/root ethereum/client-go:alltools-v1.10.25 geth --datadir /root/data/test account new

Account #4 output:

Output.6

INFO [10-16|16:17:49.034] Maximum peer count                       ETH=50 LES=0 total=50
INFO [10-16|16:17:49.034] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: dmv
Repeat password: dmv

Your new key was generated

Public address of the key:   0xF0f89f8698C418b74DDE8A61507829Ec9D066889
Path of the secret key file: /root/data/test/keystore/UTC--2022-10-16T16-17-54.483221017Z--f0f89f8698c418b74dde8a61507829ec9d066889

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!

When an account is created, it has an associated key file that is named using the following format and is located under a directory called keystore:

    UTC--{timestamp}--{address}

Execute the following command to list all the account key files:

$ ls -l data/test/keystore/

The following would be the typical output:

Output.7

total 16
-rw------- 1 polarsparc polarsparc 491 Oct 16 12:15 UTC--2022-10-16T16-15-13.065074013Z--38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40
-rw------- 1 polarsparc polarsparc 491 Oct 16 12:15 UTC--2022-10-16T16-15-54.177670500Z--c519c4be7d978cd3ab6810136878bea3b7150009
-rw------- 1 polarsparc polarsparc 491 Oct 16 12:16 UTC--2022-10-16T16-16-21.129917030Z--83d82f2ebb88f14a885bb2c8869458465db6f662
-rw------- 1 polarsparc polarsparc 491 Oct 16 12:17 UTC--2022-10-16T16-17-54.483221017Z--f0f89f8698c418b74dde8a61507829ec9d066889

As can be seen from the Output.7 above, we have the 4 key files starting with UTC and ending with the account address.

Each account has two parts to it - a private key and a public key. Also, each account is indexed by its associated address, which is formed by taking the last 20 bytes of the public key. The private key is encrypted using the passphrase that was entered during the account creation process.

To list all the accounts currently stored in our setup, execute the following command:

$ docker run -it --rm --name geth -u $(id -u $USER):$(id -g $USER) -v $HOME/Ethereum:/root ethereum/client-go:alltools-v1.10.25 geth --datadir /root/data/test account list

The following would be the typical output:

Output.8

INFO [10-16|16:19:14.556] Maximum peer count                       ETH=50 LES=0 total=50
INFO [10-16|16:19:14.556] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
INFO [10-16|16:19:14.558] Set global gas cap                       cap=50,000,000
Account #0: {38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40} keystore:///root/data/test/keystore/UTC--2022-10-16T16-15-13.065074013Z--38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40
Account #1: {c519c4be7d978cd3ab6810136878bea3b7150009} keystore:///root/data/test/keystore/UTC--2022-10-16T16-15-54.177670500Z--c519c4be7d978cd3ab6810136878bea3b7150009
Account #2: {83d82f2ebb88f14a885bb2c8869458465db6f662} keystore:///root/data/test/keystore/UTC--2022-10-16T16-16-21.129917030Z--83d82f2ebb88f14a885bb2c8869458465db6f662
Account #3: {f0f89f8698c418b74dde8a61507829ec9d066889} keystore:///root/data/test/keystore/UTC--2022-10-16T16-17-54.483221017Z--f0f89f8698c418b74dde8a61507829ec9d066889

In order to setup a private Ethereum blockchain network (consisting of a single node), we need to initialize and create the Genesis block. The Genesis block is the first block of the blockchain that has no previous block.

We will create an initialization file called genesis.json that will be located in the directory conf, with the following contents:


genesis.json
{
  "config": {
    "chainId": 21,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0,
    "clique": {
      "period": 10,
      "epoch": 30000
    }
  },
  "difficulty": "0x1",
  "gasLimit": "0xa00000",
  "extradata": "0x000000000000000000000000000000000000000000000000000000000000000038081d2ae8f6fa8eb5bf350a7d94dd7b965c8b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "alloc": {
    "38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40": { "balance": "20000000000000000000" },
    "c519c4be7d978cd3ab6810136878bea3b7150009": { "balance": "10000000000000000000" },
    "83d82f2ebb88f14a885bb2c8869458465db6f662": { "balance": "5000000000000000000" },
    "f0f89f8698c418b74dde8a61507829ec9d066889": { "balance": "3000000000000000000" }
  }
}

Let us explain and understand some of the important parameters used in the JSON file shown above.

The parameter config describes this private blockchain in terms of the network identifier, the consensus engine used, and the block number of the hard forks. The parameter chainId is the blockchain network identifier. A value of 1, 2, or 3 refer to the real-world public Ethereum networks currently in use. Since we desire a private network, we decide to choose an arbitrary value of 21 for our network. The parameter clique indicates we want to use the Proof-of-Authority (PoA) consensus algorithm.

The PoA is most suitable for Enterprise scenarios where the participants know and trust each other. As a result, the PoA consensus algorithms have faster block creation times and higher transaction throughput.

Clique is a reputation-based algorithm in which only approved and trusted accounts (known as the Signers) can validate transactions and create blocks. If there are more than one Signers, they take turns to create the next block.

We will use the bank as the trusted Signers in our private Ethereum network. The address of the Signers is specified in the extraData field.

The parameter gasLimit indicates the limit of the gas fees that will be charged for processing a block. Before a transaction is processed, a small processing fee is collected from the initiator by the miner(s). That fees is referred to as gas (also referred to as crypto-fuel) in Ethereum.

The parameter difficulty indicates the level of effort before generating a new block. Higher value indicates more effort on the part of the authorizer nodes. For our private network, we will keep this value low.

The parameter extraData indicates the concatenated list of authorized signers. At least one initial signer MUST be specified.

The parameter alloc pre-allocates ethers to the accounts in our private network.

To initialize our private Ethereum network with the Genesis block, execute the following command:

$ docker run -it --rm --name geth -u $(id -u $USER):$(id -g $USER) -v $HOME/Ethereum:/root ethereum/client-go:alltools-v1.10.25 geth --datadir /root/data/test init /root/conf/genesis.json

The following would be the typical output:

Output.9

INFO [10-16|16:40:41.121] Maximum peer count                       ETH=50 LES=0 total=50
INFO [10-16|16:40:41.123] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
INFO [10-16|16:40:41.126] Set global gas cap                       cap=50,000,000
INFO [10-16|16:40:41.128] Allocated cache and file handles         database=/root/data/test/geth/chaindata cache=16.00MiB handles=16
INFO [10-16|16:40:41.145] Opened ancient database                  database=/root/data/test/geth/chaindata/ancient/chain readonly=false
INFO [10-16|16:40:41.146] Writing custom genesis block 
INFO [10-16|16:40:41.146] Persisted trie from memory database      nodes=6 size=847.00B time="58.37µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [10-16|16:40:41.147] Successfully wrote genesis state         database=chaindata                      hash=2fd8eb..89a882
INFO [10-16|16:40:41.147] Allocated cache and file handles         database=/root/data/test/geth/lightchaindata cache=16.00MiB handles=16
INFO [10-16|16:40:41.164] Opened ancient database                  database=/root/data/test/geth/lightchaindata/ancient/chain readonly=false
INFO [10-16|16:40:41.164] Writing custom genesis block 
INFO [10-16|16:40:41.166] Persisted trie from memory database      nodes=6 size=847.00B time="101.542µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [10-16|16:40:41.166] Successfully wrote genesis state         database=lightchaindata                      hash=2fd8eb..89a882

To start a single node in our private Ethereum network, execute the following command:

$ docker run -it --rm --name geth -u $(id -u $USER):$(id -g $USER) -v $HOME/MyProjects/Ethereum:/root ethereum/client-go:alltools-v1.10.25 geth --identity "test" --datadir /root/data/test --unlock 0x38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40 --networkid "21" --maxpeers 0 --nodiscover --ipcdisable --verbosity 2 console

The following would be the typical output:

Output.10

WARN [10-16|17:27:28.019] Failed to load snapshot, regenerating    err="missing or corrupted snapshot"
WARN [10-16|17:27:28.020] Error reading unclean shutdown markers   error="leveldb: not found"
WARN [10-16|17:27:28.021] Engine API enabled                       protocol=eth
WARN [10-16|17:27:28.021] Engine API started but chain not configured for merge yet 
Unlocking account 0x38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40 | Attempt 1/3
Password: bank
Welcome to the Geth JavaScript console!

instance: Geth/test/v1.10.25-stable-69568c55/linux-amd64/go1.18.6
coinbase: 0x38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40
at block: 1 (Sun Oct 16 2022 17:27:33 GMT+0000 (UTC))
  datadir: /root/data/test
  modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

To exit, press ctrl-d or type exit
>

Given that we have indicated we want to --unlock the bank account as it is the signer (authorizer) for our private network, we will be prompted to enter its password.

Let us explain some of the options used in the command above.

The option --identity assigns an identity for our node in the private network.

The option --datadir specifies the location of the directory where the chain data for our private network will be stored.

The option --networkid specifies the network identifier and this value needs to match the value we specified in the genesis.json file.

The option --maxpeers indicates how many nodes (peers) will be connecting to this node in our private network. Since we are starting with a single node, we set it to 0 (zero) indicating no peers.

The option --nodiscover indicates our private network is not discoverable by any other nodes (peers) in the network.

The option --ipcdisable will disable the ability to connect to this node via ipc.

The console option enables the built-in Javascript runtime environment to be activated and we are presented with an REPL shell for interacting with this node.

The node exposes various commands (often referred to as APIs) that can be executed via the Javascript shell and are grouped under different namespaces as listed below:

To get information on the networking details of this node in our private network, execute the following command in the Javascript shell prompt:

> admin.nodeInfo

The following would be the typical output:

Output.11

{
  enode: "enode://328ad372d58af84cda118aa5e4997ed35aec6c38584698a6bc9087a3da7322d8d9679130fa23298a9f90327b502652695a2e6a0083a5ba85e08e3c3b3a2a1184@127.0.0.1:30303?discport=0",
  enr: "enr:-Jy4QDDUEOV1Y99MoTfNfJ4Bq_MTF2Z9If9Xx5S_8S_IQ0FuSbAOe9t-jBcnrVZYVjNcg6gjVFg4kk8VEbp7WpSHuJyGAYPly9blg2V0aMfGhAykxQSAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQIyitNy1Yr4TNoRiqXkmX7TWuxsOFhGmKa8kIej2nMi2IRzbmFwwIN0Y3CCdl8",
  id: "5fd0c59abeb446ddf2bd3064f9c687c9747077e2d824ba7fbd6d69e7f8b88a9b",
  ip: "127.0.0.1",
  listenAddr: "[::]:30303",
  name: "Geth/test/v1.10.25-stable-69568c55/linux-amd64/go1.18.6",
  ports: {
    discovery: 0,
    listener: 30303
  },
  protocols: {
    eth: {
      config: {
        berlinBlock: 0,
        byzantiumBlock: 0,
        chainId: 21,
        clique: {...},
        constantinopleBlock: 0,
        eip150Block: 0,
        eip150Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
        eip155Block: 0,
        eip158Block: 0,
        homesteadBlock: 0,
        istanbulBlock: 0,
        petersburgBlock: 0
      },
      difficulty: 1,
      genesis: "0x4e8b57176867e481471dc89bed9fda7e4491b70c99a3248aac5b36f86e5c077d",
      head: "0x4e8b57176867e481471dc89bed9fda7e4491b70c99a3248aac5b36f86e5c077d",
      network: 21
    },
    snap: {}
  }
}

To get the list of peers connected to this node in our private network, execute the following command in the Javascript shell prompt:

> admin.peers

The following would be the typical output:

Output.12

[]

The Output.12 above indicates that there are no other nodes (peers) connected to this node in our private network.

To list all the account addresses in this node of our private network, execute the following command in the Javascript shell prompt:

> personal.listAccounts

The following would be the typical output:

Output.13

["0x38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40", "0xc519c4be7d978cd3ab6810136878bea3b7150009", "0x83d82f2ebb88f14a885bb2c8869458465db6f662", "0xf0f89f8698c418b74dde8a61507829ec9d066889"]

To retrieve the details of a block by block number, execute the following command in the Javascript shell prompt:

> eth.getBlock(0)

The following would be the typical output:

Output.14

{
  difficulty: 1,
  extraData: "0x000000000000000000000000000000000000000000000000000000000000000038081d2ae8f6fa8eb5bf350a7d94dd7b965c8b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  gasLimit: 10485760,
  gasUsed: 0,
  hash: "0x4e8b57176867e481471dc89bed9fda7e4491b70c99a3248aac5b36f86e5c077d",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x0000000000000000000000000000000000000000",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000000",
  number: 0,
  parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 622,
  stateRoot: "0x6df621a03862fdabe6cac2fd03318f14f07955cee9acfc4f510bb06275494321",
  timestamp: 0,
  totalDifficulty: 1,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

Now we are at a point ready to send a transaction, transfering some cryptocurrency from one account to another.

As we indicated at the beginning, the cryptocurrency used in Ethereum is known as ether. Just like with any currency, there are various demoninations of the cryptocurrency in Ethereum , which is as follows:

For convenience and ease of use, let us assign the addresses of the 2nd and 3rd accounts to variables named buyer and dealer using the Javascript shell as shown below:

> buyer = "0xc519c4be7d978cd3ab6810136878bea3b7150009"

> dealer = "0x83d82f2ebb88f14a885bb2c8869458465db6f662"

When a transaction is sent for transferring some cryptocurrencies from one account address to another, they need to be sent in the denominations of wei. So if we want to transfer one ether from the buyer to the dealer, we will need to convert the unit from ethers to wei using the utility function web3.toWei().

To send a transaction to transfer 1 ether from the buyer to the dealer, execute the following command in the Javascript shell prompt:

> eth.sendTransaction({from: buyer, to: dealer, value: web3.toWei(1, "ether")})

The following would be the typical output:

Output.15

WARN [10-16|17:34:12.492] Served eth_sendTransaction               reqid=15 duration=2.85819ms err="authentication needed: password or unlock"
Error: authentication needed: password or unlock
  at web3.js:6365:9(45)
  at send (web3.js:5099:62(34))
  at <eval>:1:20(15)

OOPS !!! What happened here ???

By default, all accounts are in a locked state and need to be unlocked before performing transactions. Since the transaction transfers from the buyer to the dealer, we need to unlock the buyer account.

To unlock the buyer account, execute the following command in the Javascript shell prompt:

> personal.unlockAccount(buyer)

This will prompt us for the password for the buyer account. The following would be the typical output:

Output.16

Unlock account 0xc519c4be7d978cd3ab6810136878bea3b7150009
Passphrase: buyer
true

To re-send the transaction, transfering 1 ether from the buyer to the dealer, execute the following command in the Javascript shell prompt:

> eth.sendTransaction({from: buyer, to: dealer, value: web3.toWei(1, "ether")})

The following would be the typical output:

Output.17

"0xdfa3e022863651668481c378b9c6c0618bb566b48e87902fe144d8549f761cc0"

The big hex value in Output.17 above is the transaction number for the just sent transaction.

Remember, we have not started any miner (or the authorizer) on this network yet and hence the just sent transaction will be in a pending state.

To display all the pending transactions on this network, execute the following command in the Javascript shell prompt:

> eth.pendingTransactions

The following would be the typical output:

Output.18

[{
    blockHash: null,
    blockNumber: null,
    chainId: "0x15",
    from: "0xc519c4be7d978cd3ab6810136878bea3b7150009",
    gas: 21000,
    gasPrice: 1000000000,
    hash: "0xdfa3e022863651668481c378b9c6c0618bb566b48e87902fe144d8549f761cc0",
    input: "0x",
    nonce: 0,
    r: "0x7d1e3a62cddf671dfe7680fd5b7d07f0c3678cbc1162368fb632a939c512a4dc",
    s: "0x226ccbf2e55d5941481f9a0e0963a2d2f0548403466ae7c3f68a9bccf271efc0",
    to: "0x83d82f2ebb88f14a885bb2c8869458465db6f662",
    transactionIndex: null,
    type: "0x0",
    v: "0x4d",
    value: 1000000000000000000
}]

To display information about the pending transaction(s) in the transaction pool, execute the following command in the Javascript shell prompt:

> txpool.inspect

The following would be the typical output:

Output.19

{
  pending: {
    0xC519C4be7D978cD3AB6810136878bEA3b7150009: {
      0: "0x83d82f2Ebb88F14a885Bb2c8869458465dB6F662: 1000000000000000000 wei + 21000 gas × 1000000000 wei"
    }
  },
  queued: {}
}

For convenience, one can create custom Javascript utility functions to extract and display information. The following is a custom Javascript utility function to display account balances (in ethers):


showBalances
function showBalances() {
  var i = 0;
  eth.accounts.forEach(function(e) {
     console.log("---> eth.accounts["+i+"]: " + e + " \tbalance: " + web3.fromWei(eth.getBalance(e), "ether") + " ether");
     i++;
  })
};

Paste the above Javascript code in the shell prompt and the following would be the typical output:

Output.20

undefined

To display account balances using the Javascript utility function showBalances, execute the following command in the Javascript shell prompt:

> showBalances()

The following would be the typical output:

Output.21

---> eth.accounts[0]: 0x38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40 	balance: 20 ether
---> eth.accounts[1]: 0xc519c4be7d978cd3ab6810136878bea3b7150009 	balance: 10 ether
---> eth.accounts[2]: 0x83d82f2ebb88f14a885bb2c8869458465db6f662 	balance: 5 ether
---> eth.accounts[3]: 0xf0f89f8698c418b74dde8a61507829ec9d066889 	balance: 3 ether
undefined

Now we are ready to start a miner (the authorizer) for this network.

To start the miner with one mining thread, execute the following command in the Javascript shell prompt:

> miner.start(1)

The following would be the typical output:

Output.22

null

Wait about 5 seconds and check the status of the transaction pool by executing the following command in the Javascript shell prompt:

> txpool.inspect

The following would be the typical output:

Output.23

{
  pending: {},
  queued: {}
}

To stop the miner (the authorizer), execute the following command in the Javascript shell prompt:

> miner.stop()

The following would be the typical output:

Output.24

null

To retrieve the transaction details of the just sent transaction 0xdfa3e022863651668481c378b9c6c0618bb566b48e87902fe144d8549f761cc0, execute the following command in the Javascript shell prompt:

> eth.getTransaction("0xdfa3e022863651668481c378b9c6c0618bb566b48e87902fe144d8549f761cc0")

The following would be the typical output:

Output.25

{
  blockHash: "0xba1a94b2872683fd84851ea90982751f6e1730f252a999d6e974e70b471584c9",
  blockNumber: 2,
  chainId: "0x15",
  from: "0xc519c4be7d978cd3ab6810136878bea3b7150009",
  gas: 21000,
  gasPrice: 1000000000,
  hash: "0xdfa3e022863651668481c378b9c6c0618bb566b48e87902fe144d8549f761cc0",
  input: "0x",
  nonce: 0,
  r: "0x7d1e3a62cddf671dfe7680fd5b7d07f0c3678cbc1162368fb632a939c512a4dc",
  s: "0x226ccbf2e55d5941481f9a0e0963a2d2f0548403466ae7c3f68a9bccf271efc0",
  to: "0x83d82f2ebb88f14a885bb2c8869458465db6f662",
  transactionIndex: 0,
  type: "0x0",
  v: "0x4d",
  value: 1000000000000000000
}

To retrieve the details of the latest block, execute the following command in the Javascript shell prompt:

> eth.getBlock('latest')

The following would be the typical output:

Output.26

{
  difficulty: 2,
  extraData: "0xd883010a19846765746888676f312e31382e36856c696e75780000000000000050cbcc73031d9c83af96d44a51061154d8cb899614e82bbf0830d64f2f6237b621d8d4a890245df13bdcf5b95c6351ed2c25d4bfbea112e9516f9e0663be31a101",
  gasLimit: 10516506,
  gasUsed: 0,
  hash: "0xe4b9346e3791c5ec08ee5c131af21c8d430489bbfdb9158b203118fecba94a92",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x0000000000000000000000000000000000000000",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000000",
  number: 3,
  parentHash: "0xba1a94b2872683fd84851ea90982751f6e1730f252a999d6e974e70b471584c9",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 606,
  stateRoot: "0x10c6a516c3b4d366c30d1baa78fd698ff970dc1e5b19dfe616f539d085290fdb",
  timestamp: 1666008352,
  totalDifficulty: 7,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

Now, we check the account balances using the Javascript utility function showBalances by executing the following command in the Javascript shell prompt:

> showBalances()

The following would be the typical output:

Output.27

---> eth.accounts[0]: 0x38081d2ae8f6fa8eb5bf350a7d94dd7b965c8b40 	balance: 20.000021 ether
---> eth.accounts[1]: 0xc519c4be7d978cd3ab6810136878bea3b7150009 	balance: 8.999979 ether
---> eth.accounts[2]: 0x83d82f2ebb88f14a885bb2c8869458465db6f662 	balance: 6 ether
---> eth.accounts[3]: 0xf0f89f8698c418b74dde8a61507829ec9d066889 	balance: 3 ether
undefined

As is evident from the Output.27 above, the account balance for the buyer (2nd account) has decreased, while the account balance for the dealer (3rd account) has increased.

Hmm !!! Something is odd about the balances for the first two accounts above. Let us try and break it down as follows:

From the Output.25 above, we see that the transaction was processed in block number 2. To find the processing fees (gas) charged for the transaction, we need two pieces of information - the gasUsed (amount of processing done - similar to hours of work done) and the gasPrice (cost for unit of processing - similar to wages per hour). The processing fees (gas) is then computed as (gasUsed * gasPrice).

To retrive the value for gasUsed for the transaction, execute the following command in the Javascript shell prompt:

> eth.getBlock(2)

The following would be the typical output:

Output.28

{
difficulty: 2,
extraData: "0xd883010a19846765746888676f312e31382e36856c696e757800000000000000aa84dc9a9742924f3bc686f5fe7042eebe4cc1792585190a2433d0f453fcd2e22479b5d0f75207fe5012127bf03dc8b63ae683b52f813f55f952aaddb4cc14d200",
gasLimit: 10506247,
gasUsed: 21000,
hash: "0xba1a94b2872683fd84851ea90982751f6e1730f252a999d6e974e70b471584c9",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x0000000000000000000000000000000000000000",
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000000",
number: 2,
parentHash: "0x003e26a43440bafbb4df04640f7b26271a4a23383365c4abf1b594e4e7d1d1d8",
receiptsRoot: "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 718,
stateRoot: "0x10c6a516c3b4d366c30d1baa78fd698ff970dc1e5b19dfe616f539d085290fdb",
timestamp: 1666008342,
totalDifficulty: 5,
transactions: ["0xdfa3e022863651668481c378b9c6c0618bb566b48e87902fe144d8549f761cc0"],
transactionsRoot: "0xd66b671a57d98efcff80be3dd95b98975684deabd8803ee5cf37f54970605330",
uncles: []
}

Next, to retrive the value for gasPrice for the transaction, execute the following command in the Javascript shell prompt:

> eth.getTransactionFromBlock(2)

The following would be the typical output:

Output.29

{
  blockHash: "0xba1a94b2872683fd84851ea90982751f6e1730f252a999d6e974e70b471584c9",
  blockNumber: 2,
  chainId: "0x15",
  from: "0xc519c4be7d978cd3ab6810136878bea3b7150009",
  gas: 21000,
  gasPrice: 1000000000,
  hash: "0xdfa3e022863651668481c378b9c6c0618bb566b48e87902fe144d8549f761cc0",
  input: "0x",
  nonce: 0,
  r: "0x7d1e3a62cddf671dfe7680fd5b7d07f0c3678cbc1162368fb632a939c512a4dc",
  s: "0x226ccbf2e55d5941481f9a0e0963a2d2f0548403466ae7c3f68a9bccf271efc0",
  to: "0x83d82f2ebb88f14a885bb2c8869458465db6f662",
  transactionIndex: 0,
  type: "0x0",
  v: "0x4d",
  value: 1000000000000000000
}

From the Output.28 above, we see that the gasUsed is 21000 and from the Output.29 above, the gasPrice is 1000000000. The processing fees (gas) is then (21000 * 1000000000) which equals 21000000000000 wei's.

Execute the following expression in the Javascript shell prompt:

> 9 - web3.fromWei(21000000000000)

The following would be the typical output:

Output.30

8.999979

This is the remaining balance in the account of the buyer.

To exit the Javascript shell as well as the node, execute the following command in the Javascript shell prompt:

> exit

BINGO !!! We have successfully demonstrated the workings of the Ethereum blockchain platform using our single node private network.


References

Official Ethereum Developer Documentation

Ethereum Private Network

Command-line Options for the Ethereum Go (geth) client

Ethereum JSON-RPC Server

web3.js Ethereum JavaScript API



© PolarSPARC