Skip to main content

Ethereum fundamentals

Keys and addresses

Private key ──[secp256k1]──▶ Public key ──[Keccak-256]──▶ Address

The address is the last 20 bytes of the Keccak-256 hash of the public key, with the leading 0x04 uncompressed-point prefix stripped before hashing.

Private key
bcd3a9cc19cdf4401106d5315e947d5688112f0bec622d15e19d6f0afe8820c6

Public key
0x0435127b603a3f9f9e38f7683c885bcae69279a1027ccf4693d153e3afc045fc39db1c668a169993f324aa59ddfc44aa91ba178921e31738fd08d335afde244302

Address
0x28826f66983d39e0cf67df3a9e20288337d0c584

Ethereum uses Keccak-256, the original submission, not the finalised SHA3-256 standard. The two differ in padding and produce different digests for the same input, so a library's sha3 function may or may not be what you need — check whether it means NIST SHA-3 or Keccak.

Generic BIP-39 helper tools often truncate or compress the public key, which yields a different address. Derive addresses with an Ethereum-aware library.

Account types

Externally owned account (EOA)Contract account
Controlled byA private keyIts own code
Can initiate a transactionYesNo — only reacts to calls
Has codeNoYes
Has storageNoYes

Every transaction originates from an EOA. A contract calling another contract is part of the same transaction, not a new one.

Nonce

A scalar equal to the number of transactions sent from an address, or for a contract account, the number of contracts it has created.

The nonce increments when:

  • An EOA sends a transaction.
  • A contract creates another contract.

The nonce does not change when:

  • A contract is merely called, or a transaction is received.
  • A read-only (eth_call) query is made.

The nonce serves two purposes: it orders an account's transactions, and it makes replay impossible — a nonce can only be used once. A transaction with a nonce gap sits in the mempool until the missing one arrives, which is why one stuck transaction blocks every later one from the same account.

Contract addresses created with CREATE derive from the creator's address and nonce, which is what makes them predictable before deployment. See Gas optimization for the CREATE2 variant.

Gas

Gas measures computational work. Every opcode has a fixed cost, so the total is known from the execution trace.

Transaction fee = gas used × gas price
1 Gwei = 0.000000001 ETH

At 20 Gwei, one gas unit costs 0.00000002 ETH. A plain ETH transfer always costs exactly 21 000 gas, so its fee at that price is 0.00042 ETH.

The gas limit caps how much the sender is willing to spend. Unused gas is refunded; running out is not — the transaction reverts and the gas consumed up to that point is still charged.

EIP-1559 fee model

Since the London upgrade the fee is split:

fee = gas used × (base fee + priority fee)
  • Base fee is set by the protocol from recent block fullness and is burned, not paid to the validator.
  • Priority fee (the tip) goes to the validator and is what determines inclusion speed.
  • Max fee per gas is the ceiling the sender accepts; the difference between it and the actual base fee is refunded.

Legacy gasPrice transactions still work and are treated as maxFeePerGas = maxPriorityFeePerGas = gasPrice.

Function signatures

A function selector is the first 4 bytes of the Keccak-256 hash of the canonical signature — the name plus parameter types, no spaces, no parameter names.

setCompleted(uint256)
──[Keccak-256]──▶ fdacd5762b86e21561bc37c704505a12d8a5b260c671df7e3ed98e1cbb14f7c5
first 4 bytes ──▶ 0xfdacd576

Calldata is the selector followed by the arguments, each padded to 32 bytes:

0xfdacd576
0000000000000000000000000000000000000000000000000000000000000002
└─ the argument 2, left-padded to 32 bytes

The selector appears in the contract's bytecode because the dispatcher compares incoming calldata against each known selector.

Use uint256, not uint, when computing a selector by hand. They are the same type but only the canonical form hashes correctly.

Selector collisions are possible — 4 bytes is small — and have been used in proxy-contract attacks. This is why the transparent proxy pattern separates admin and implementation calls.

Chain ID and network ID

They are not the same thing, and the difference matters.

  • Chain ID (EIP-155) is included in the signed transaction. It prevents a transaction signed for one chain from being replayed on another.
  • Network ID is used at the peer-to-peer layer for node discovery and handshakes.

Most networks set both to the same value. Ganache historically did not:

Ganache chain ID 1337 network ID 5777

A wallet that signs with the wrong chain ID produces a transaction the node rejects as invalid, which surfaces as a signature error rather than a configuration one.

Current values worth knowing:

NetworkChain ID
Ethereum mainnet1
Sepolia testnet11155111
Holesky testnet17000
Polygon mainnet137
Polygon Amoy testnet80002

Ropsten, Rinkeby, Kovan and Goerli have all been shut down or deprecated. Sepolia is the general-purpose testnet; Holesky targets staking and validator testing.

Layer 2

Rollups execute transactions off-chain and post data back to Ethereum, which remains the settlement and data-availability layer.

TypeHow validity is establishedWithdrawal delay
Optimistic rollupAssumed valid; fraud proofs during a challenge window~7 days
ZK rollupValidity proof verified on-chainMinutes to hours

Rollups plus data-availability sharding is the direction Ethereum's roadmap took. EIP-4844 (proto-danksharding, shipped in the Dencun upgrade) added blob transactions, which cut rollup data costs by an order of magnitude.

See Polygon for one implementation.