Ethereum 101 - Part 4 - Accounts, Transactions, and Messages

Accounts, Transactions, and Messages

The Ethereum state is made up of accounts, and the transactions among those accounts propel the network forward, ensuring network validators receive appropriate compensation for their Proof of Work computations securing the blockchain.

The blockchain is a state transition system. The “state” is the ledger of all existing Ethereum accounts, smart contracts, and ether ownership. In a “state transition function” that state is used to execute a transaction and the output of that transaction becomes the new state. As transactions are submitted to the network by externally owned accounts, they move the Ethereum blockchain to its newest state.

Quick Overview

There are two different types of accounts:

Externally owned accounts are controlled by their private keys, while contract accounts are controlled by their contract EVM bytecode, a topic that will be discussed in another section.

Address (do not send money to this address, it may be lost):
0xab6291d3B3290e7F2287dE751Fb5FDDA4B91ebB6

The address is your public facing element of your account. If you are to receive Ether, you will direct that transaction to this address. The address is simply the Keccak-256 hash of the public key, which is not listed in this section.

Private Key (with this key, you have control over the above address):
aa50f1a46ecb19a2464cfdd43f0d31ad32f4bb598df3ed5a448a43ab5d02f0ef

Supplemental Technical Information

Mnemonic Seed Phrases & BIP39

Some decentralized apps and wallets use mnemonic phrases or JSON files for account recovery (e.g. MetaMask uses a 12 word seed phrase for account restoration). Similar as you would with private keys, mnemonic phrases and keystore files (typically a JSON file) should be duly protected.

Resources:

Should someone learn your mnemonic phrase or obtain your JSON keystore file, they may be able to recover your account and gain access to your funds. For more information, please reference the knowledge bases of MetaMask (https://support.metamask.io/) and MyEtherWallet (https://myetherwallet.github.io/knowledge-base/).

Primer on Asymmetric Cryptography

Accounts are derived through complex and inherently secure asymmetric cryptography. The creation of an Ethereum account is a three step process:

Using our accounts’ derived asymmetric private key and address, we can begin executing transactions. The term transaction refers to a signed data package that is sent from an externally owned account. Similar to a transaction, a message call is produced by a contract, not an externally owned account. Contracts can even make message calls to other contracts. The white paper describes contracts not as objects that must be fulfilled, but instead as a block of code on the blockchain that is executed when called by an externally owned account or another contract (via a message call).

In the event we are conducting a raw transaction between two external accounts, the process is straightforward. First, we need three parameters: the account that is sending the transaction, the account that will be receiving the transaction value, and the value of the transaction. Additional parameters are required: nonce, gasLimit, and the gasPrice, though we do not need to derive these values on our own as they will be populated by the geth console.

Sending a transaction with ethereumjs-tx

For the purposes of this document, we will be using ethereumjs-tx to execute this transaction. Installation is simple, please use the command below:

$ npm install ethereumjs-tx

Next, let’s get a geth console running and obtain some values to help us better define our transaction parameters. Let’s use the Rinkeby testnet for this exercise. You will need to obtain ether from the Rinkeby faucet @ https://faucet.rinkeby.io/.

Open up a terminal and input the following geth commands:

> geth --fast --cache=1024 --rinkeby console 2>>eth.log

Utilize a second terminal to view the geth feed:

> tail -F eth.log

Obtain our transaction nonce using the below command in our geth node:

> web3.eth.getTransactionCount(“<insert account here>”)

Now that we’ve found our transaction nonce, let’s assemble the code that will push our transaction onto the ethereum network. Understanding the transaction nonce and how it prevents double-spending on the Ethereum blockchain is important. Assume that an Account A is sending 3 ether to Account B, and Account A only has that 3 ether in its account. Account A signs and broadcasts this transaction to the network. Subsequently, while using a higher gas price, Account A then signs and broadcasts a second transaction to C in the amount of 3 ether. The higher gas price warrants the second transaction a higher queue in the pending transaction pool, effectively executing a double spend.

The nonce is what prevents this double spending from happening, as account transactions need to be sequential. In our above example, assuming the account has a nonce of 0, the first transaction will be written to the blockchain. The second transaction, even with the higher gas price, will be rejected because the nonce is +1 more than the first transaction’s nonce. The blockchain will interpret that Account A will not have enough ether to execute the second transaction, even though it was sent with a higher gas price, and will then reject that second transaction.

In our nodejs console:

> const EthTxn = require(“ethereumjs-tx”)
> const privKey = Buffer.from(“<INSERT PRIVATE KEY>”, “hex”)
> const txnParams = {nonce: “0x00”, gasPrice: “0x2540be400”, gasLimit: “0x222e0”, to: “<INSERT DESTINATION ADDRESS HERE>”, value: “0x2fe01dba2bb1dffe”, data: “0x00”, }
> const tx = new EthTxn(txnParams)
> tx.sign(privKey)
> const serializedTx = tx.serialize()
> const rawTxn = “0x” + serializedTx.toString(“hex”);
> console.log(rawTxn)
// this will output a long transaction string
0xf86d018520540be400839752e094a18d70840b9bc475ba15f4f6a98d2967744fe4c1882fe01dba2bb1dffe001ba0984e42f70a04d17e56b965423ae83527ee701cfb56e2b701b8b46e9c94461303a01ffd3efc1bcc7eb5f85fa1929cb2ca52706a59f0c48febe488c3c56aee5d164e

The above console.log(rawTxn) command will return a raw transaction string. Input this raw transaction string into your geth console using the below command:

> eth.sendRawTransaction(“0xf86d018520540be400839752e094a18d70840b9bc475ba15f4f6a98d 2967744fe4c1882fe01dba2bb1dffe001ba0984e42f70a04d17e56b965423ae83527ee701cfb56e2b701b8b46e9c94461303a01ffd3efc1bcc7eb5f85fa1929cb2ca52706a59f0c48febe488c3c56aee5d164e”)

In your second terminal you will find output similar to the below:

INFO [XX-XX|XX:XX:XX] Submitted transaction ...

To summarize, the above tutorial explains how to send transactions from an externally owned account. It’s important to understand that contracts do not initiate transactions. Contracts are able to send messages to other contracts, but to do this, the contract must receive a message from an externally owned account.

Contract messages are different, they do not have a gas limit, as the gas costs set by the externally owned account initiating the transaction must be sufficient enough to carry the whole execution through to completion. In the event a message execution runs out of gas, then that particular message will halt and revert back to its previous state, unwinding all prior computational steps effectively restoring its previous state. This is an unsuccessful transaction.

Since we sent the above transaction on the Rinkeby testnet, you could simply use Etherscan to view your address, the transactions you’re sending and receiving at that address, as well as the externally owned accounts and contracts that received your test ether. Many decentralized apps reference Etherscan to obtain a quick glimpse of your activity on the blockchain. Take a moment to review: https://etherscan.io

Additional Web3 Libraries

Web3js - JavaScript

Web3py - Python

Web3j - Java

Additional reading: