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 (acronym: EOA)
- Contract 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:
- https://iancoleman.io/bip39/ & https://github.com/iancoleman/bip39
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:
- First, a 64 character hexadecimal private key is randomly generated.
- Second, the public key is generated by taking the 64 character hexadecimal private key and applying elliptic curve multiplication (this is an irreversible calculation).
- Third, take the Keccak-256 hash of the newly generated public key, take the final, furthest right 40 characters of this hash, and prefix these 40 characters with ‘0x’. This is the account address.
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.
- nonce: this is the transaction count of the account sending the transaction (not to be confused with the Proof of Work nonce, as this is a different nonce).
- gasLimit (STARTGAS): an upfront value paid by the externally owned account setting the maximum price paid to execute the transaction; if all gas is exhausted the transaction is reverted back to its previous state. Any unused gas is typically returned to the transaction sender.
- gasPrice (GASPRICE): the value of each computation step (an EVM opcode) paid by the externally owned account to execute the transaction.
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
- Github: https://github.com/ethereum/web3.js/
- Docs: https://web3js.readthedocs.io/en/1.0/
Web3py - Python
- Github: https://github.com/ethereum/web3.py
- Docs: https://web3py.readthedocs.io/en/stable/
Web3j - Java
- Github: https://github.com/web3j/web3j
- Docs: https://docs.web3j.io/
Additional reading:
- Ethereum White Paper: https://github.com/ethereum/wiki/wiki/White-Paper#messages-and-transactions
- Ethereum Yellow Paper: https://ethereum.github.io/yellowpaper/paper.pdf
- Ethereum Beige Paper: https://github.com/chronaeon/beigepaper/blob/master/beigepaper.pdf
- Kauri original title: Ethereum 101 - Part 4 - Accounts, Transactions, and Messages
- Kauri original link: https://kauri.io/ethereum-101-part-4-accounts-transactions-and-mess/7e79b6932f8a41a4bcbbd194fd2fcc3a/a
- Kauri original author: Wil Barnes (@wil)
- Kauri original Publication date: 2019-02-13
- Kauri original tags: smart-contract, ethereum, 101, web3, state, message, transaction
- Kauri original hash: QmTF8hThon8NnFva8AqmxHzYb32fr32xUei3FkyMY7M7r7
- Kauri original checkpoint: QmRS3wCLX2MRi62bg9NTM89qNkgm3XjpKXciLvCKAr1f1g