POSTED 2 months ago

Ethereum 101 - Part II - Ethereum Technical Details

Part II - Ethereum Technical Details

Consensus Protocols

The engine that drives consensus among the nodes on the Ethereum network. Ethereum is currently operating on a Proof-of-Work consensus protocol, but in the future will be shifting to a Proof-of-Stake protocol.

Current Protocol: Proof of Work (Ethash)

The current Ethereum blockchain uses a consensus algorithm built specifically for the Ethereum blockchain called Ethash. The Ethash PoW algorithm introduces the property of “Memory Hardness” to the Ethereum blockchain. Memory hardness dictates that your computational performance is limited by how fast your machine can move data around in memory, as opposed to how rapidly it can perform computations. By doing this, the Ethereum blockchain aims to prevent large organizations and large mining pools from obtaining undue influence over the network. Reference documentation: https://github.com/ethereum/wiki/wiki/Ethash

Target State Protocol: Proof of Stake (Casper)

In a Proof-of-Stake consensus algorithm, users who desire to validate blocks are required to deposit a stake of their own ether. That stake is locked, and a consensus algorithm is then used that only these staked users can participate in. There are two types of Proof-of-Stake algorithms, a chain-based proof and a Byzantine Fault Tolerance-style proof.

  • A chain-based Proof-of-Stake staked users are selected pseudo-randomly during a set time block, that user is given the right to create a single block, and that block that is created must be pointed to a previous block.
  • A Byzantine Fault Tolerance-style (BFT-style) proof randomly assigns users the right to propose blocks. However, obtaining agreement on the canonical block takes place through a multiple round process where each validator party to the network places a vote for a specific block during that round, and in the final round, the validators will have arrived at a permanent block to add to the chain.

The Ethereum roadmap includes a transition to Proof of Stake at an indefinite time in the future. The Ethereum Proof of Stake FAQ is a good reference point for more in-depth discussion: https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ

Ethereum Mainnet & Testnets

Clients are generally by default pointed to the Ethereum mainnet (the live Ethereum network). The testnets are public test networks, each with their own consensus protocol and supported clients. Developers should pick the right testnet that fits their development environment and project goals.

The mainnet is the live ethereum blockchain. Mainnet is the current ethereum production environment. The testnets are exactly as the name implies: test blockchain networks. In our exercise above we spun up a private development blockchain. That is figuratively a testnet as well, albeit a private one without peer nodes. The testnets highlighted within this section are publicly accessible. The general rule of thumb is that by default any client you use will automatically be pointed at the mainnet.

Here is a brief overview of the main Ethereum testnets:

Testnet Ropsten Kovan Rinkeby
Consensus Protocol Proof of Work
(best emulates current production environment)
Proof of Authority Proof of Authority
Supported Clients Both Geth / Parity Parity only Geth only
Mineable / Faucet Mineable
(ether can also be requested via fauced
Not mineable
(ether is requested via faucet)
Not mineable
(ether is requested via faucet)
Spam attacks Not immunte to spam attacks Immune to spam attacks Immune to spam attacks
Website Link Link Link

Source: https://www.ethnews.com/ropsten-to-kovan-to-rinkeby-ethereums-testnet-troubles Source: https://ethereum.stackexchange.com/questions/27048/comparison-of-the-different-testnets

The Ropsten testnet, by virtue of using a proof of work consensus protocol and being mineable, generally best emulates the current ethereum production network. Kovan and Rinkeby both utilize a proof of authority protocol, essentially meaning that instead of nodes solving arbitrarily difficult mathematical proof of work puzzles, a set of authorities (called ‘sealers’) are given the explicit permission to create new blocks and update the state of the blockchain.

Under a proof of authority protocol, attackers operating from an unwanted connection are unable to overwhelm or spam the network. The implementation of proof of authority testnets was the result of a series of attacks exploiting the proof of work algorithm on prior testnets (these attacks originated on Morden, which has since been voluntarily brought offline). To learn more of the historical details surrounding the testnets, please see the additional reading section.

Additional Reading:

Additional Protocols to Consider When Building your Dapp

In addition to all the development goodies we’ve described thus far, there is a whole ecosystem of similar services that can be leveraged when building your dapp, like decentralized file storage (e.g. IPFS, Swarm), decentralized computation (e.g. Golem), and decentralized messaging (e.g. Whisper, Matrix).

Additional reading:

Accounts, Transactions, and Messages

The Ethereum state is made up of accounts, and the transactions among those accounts is what propel the network forward, ensuring network validators receive appropriate compensation for their proof of work computations that secure 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 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.

Brief Example of Ethereum Accounts

It’s important to understand the two different types of accounts: externally owned accounts and contract accounts. Essentially, externally owned accounts are controlled by their respective private keys, while contract accounts are controlled by their respective contract EVM byte code, of which we will explain later.

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: aa50f1a46ecb19a2464cfdd43f0d31ad32f4bb598df3ed5a448a43ab5d02f0ef

Odds and Ends 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. 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. Akin 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.

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(“”, “hex”) const txnParams = { nonce: “0x00”, gasPrice: “0x2540be400”, gasLimit: “0x222e0”, to: “”, 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 reiterate, 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 gasLimit, 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 ethereum 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 you sent your test ether to. Many decentralized apps reference etherscan as an easily accessible and reliable way to obtain a quick glimpse of your activity on the blockchain. Take a moment to review: https://etherscan.io

Additional reading:

Outline
  • Part II - Ethereum Technical Details

OWNER
wil