Ethereum & Solidity mechanics
Recap: Ethereum in one slide
States S = a map from addresses to state
Copyright By Assignmentchef assignmentchef
Inputs I (transactions)
Transition f:
validate signature
run to.code(from, data, value, startgas, gasprice)
Start state:
y affect the state of
value startgas gasprice
any address
Recap: The full* Ethereum blockchain structure
prev height nonce difficulty
state root
miner extra
transaction root receipt root
Recap: The full* Ethereum blockchain structure
prev height nonce difficulty
state root
miner extra
transaction root receipt root
Recap: The full* Ethereum blockchain structure
prev height nonce difficulty
state root
miner extra
transaction root receipt root
final state
log output
Ethereum addresses can be accounts or contracts
Note: no UTXOs in
H(pub_key)
H(creator, nonce)
Merkle storage root
ETH balance
#transaction sent
Volatile fields
Three* types of transaction in Ethereum
Three* types of transaction in Ethereum
transfer_val
Three* types of transaction in Ethereum
transfer_val
transfer_val
NameCoin in introduced three new opcodes NAME_NEW: H(r, jbonneau)
12 block delay (frontrunning)
NAME_FIRST_UPDATE: r, jbonneau, {ip : 68.178.254.235}
NAME_UPDATE: jbonneau, {ip6 : 2001:4860:0:1001::68}
Ethereum Virtual Machine
EVM is stack-based, like BTC script Features
1024-depth stack
32-byte words
Accelerated crypto
Big num multiply
GF-256 operations
CALLDATALOAD
CALLDATALOAD
CALLDATALOAD
EVM provides basic API for I/O
tx info: sender, value, gas limit
resource use: gas remaining, memory used
block info: depth, timestamp, miner, hash
send messages (call other contracts and/or send money)
write to logs
self destruct
Subtleties to contract calls
Data: unlimited params/return values
Direct mapped to memory address + size
Exceptions: out of gas, bad jump, etc.
No state changes persisted
Control returns to caller
Call stack limit: 1024
Calls from 1024th frame will fail
EVM memory model offers a lot of space
Storage: {0,1}256{0,1}256 map (persistent) Memory: {0,1}256{0,1}256 map (volatile between tx)
in other words, both can store 2264 bits!
arranged in 256-bit words
all memory is zero-initialized
Storage in Ethereum is very expensive. Limiting memory use is critical
Efficient map commitments
How can Ethereum commit to so much state? Recall: storage is a {0,1}256{0,1}256 map Requirements:
O(lg k) update cost
O(lg k) proofs (even for zero values)
Key insight:
keys supported
keys with a non-zero value
commitment size
Optimize for efficient storage of zeroized values
Non-solution: use a binary tree, paths encode address 0
Requires O(2n) computation
Optimization #1: pre-compute all sizes of empty tree
Dynamic programming formula: 0
Empty[x] = H(Empty[x-1]||Empty[x-1])
This works!
Proofs are length O(lg n)
Optimization #2: shrink all single subtrees; store prefix
01, Alice
diverge node
0 , works!
Proofs are length O(lg k)
,s ATRICIA tree has a few quirks
Used in two main places
overall state
per-contract storage 16-ary
proofs ~4x longer paths can be < 256 bits 1, 01 are distinct Really 2257-1 addressesSolidity should look familiar Syntax looks like C++, JavaScript etc. Contracts look like classes/objects Can mark functions internal Static typing Most types can be cast e.g. bool(x) Basic program structureSolidity should look familiar Imperative. Syntax looks like C++, JavaScript etc. Object-oriented. Contracts are like objects/classes Static typing. Most types can be castSolidity programs let you define a contract contract HelloWorld {Storage: Member variables stored on the blockchain contract HelloWorld {int count;Everything in Solidity is initialized to zero function hello() public {Functions: enable interaction with outside world contract HelloWorld {int count;function hello() public returns int{ count += 1; return count;function megaHello() private { count += 10; Constructors: enable one-time setup contract HelloWorld {int count;constructor(int initialCount) public { count = initialCount;function hello() public { Set of public functions form a contracts ABIcontract myToken {function totalSupply();Application Binary Interfacefunction balanceOf(address tokenOwner);function allowance(address tokenOwner, address spender);function transfer(address to, uint tokens);function approve(address spender, uint tokens);function transferFrom(address from, address to, uint tokens);Data types in SolidityBasic types should look familiar (value types)true/false valueint, int8, int16, … int256signed integersuint, uint8, uint16, … uint256unsigned integersbyte, bytes2, bytes3, … bytes32fixed-size byte arrays Whats missing? Floating point Pointersaddress stores a contract or account address contract Squares {address a;function sendMoney(uint amount) private { a.transfer(amount); struct allows grouping related values contract Election {struct Voter { address key; bool hasVoted; uint precinctNumber;v.hasVoted = true; enum streamlines hard-coding values contract Casino {enum Suit {Hearts, Diamonds, Clubs, Spades}function deal() public { Suit leadSuit; leadSuit = Suit.Hearts; Dynamic arrays built-in contract Squares {function countSquares(uint n) public { uint[] memory s = new uint[](n); uint l = s.length; mapping relates keys to values contract Bank {mapping (address => uint) balances;
function deposit() public returns uint{
balances[msg.sender] += msg.value;
return balances[msg.sender];
Mapped values stored at storage address H(key)
mapping(string => uint) balances;
H(balances|Bob)
H(balances|Joe)
H(balances|Alice)
balances[Andrew] = 0 if Andrew doesnt exist
to delete a key, set balances[Andrew] = 0
cannot iterate over all items in a map
cannot delete an entire map
Object-oriented features
Inheritance
abstract contract Animal {
contract Cat is Animal {
function talk() public override
function talk() purbeltiucrnosv(ebryrtiedse32 sound){
function talk() public virtual returns(bytes32);
contract Kitten is Cat {
return meow; returns(bytes32 sound){ return mewwwwwww;
Interfaces
interface Token {
function name() public view returns (string)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256
function transfer(address _to, uint256 _value) public returns (bool
Only virtual functions; multiple inheritance is allowed
Function modifiers affect visibility
who can access?
only this contract
this construct or derived contracts
only other contracts
Function modifiers affect capabilities
limitations
cant write any persistent state
cant read or write any state
Solidity conventions
Polite contracts call throw errors
uint8 numCandidates;
uint32 votingFee;
mapping(address => bool) hasVoted;
mapping(uint8 => uint32) numVotes;
/// Cast a vote for a designated candidate
function castVote(uint8 candidate) {
if (msg.value < votingFee)if (hasVoted[msg.sender])hasVoted[msg.sender] = true;numVotes[candidate] += 1;Error ensures no effects persisted except gas consumption Several ways to throw an error bool shouldBeTrue;require(shouldBeTrue);assert(shouldBeTrue);if(!shouldBeTrue) {if(!shouldBeTrue) {//burn all remaining gas//burn all remaining gas (deprecated)Modifiers ease repetitive safety checksaddress public owner;uint public electionEnd;modifier onlyBy(address _account){ require(msg.sender == _account);modifier onlyAfter(uint _block) { require(block.blocknumber >= _block);
function endElection()
onlyBy(owner) onlyAfter(electionEnd){
Built-in support for calling other contracts
a.transfer(x) sends x to address a
returns 0 if this fails due to call stack
foo.call{value:3, gas:20764}( bytes4(sha3(bar())));
also callcode, delegatecall
default is 0 value, all available gas
new constructor deploys a new contract Careful, its expensive!
Smart contracts code is fixed forever. Calls required to update functionality
Solidity gotchas
Member variables public by default getters automatically provided
Functions must be marked payable to accept funds
Member variables go to storage by default
Method variables go to memory
Fallback function()
Called if no function specified (e.g. send)
Called if non-existent function called
msg.sender vs. tx.origin
https://solidity.readthedocs.io/en/develop/solidity-in-depth.html
Solidity and EVM may outgrow Ethereum itself
Enterprise Ethereum Alliance
-Goal: support EVM, Solidity and tools for private blockchains maintain compatibility with Ethereum network
Dont like Solidity? Write your own language! Untyped, looks like python Typed, looks like JS Typed, looks like Go
Vyper Solidity Bamboo Research here
Lower-Level Language
Ethereum VM Bytecode Stack Language
Looks like Forth. Defined in Yellowpaper
Gas and transaction limits
Ethereum is like Ryanair: pay to board, then keep paying
Gas in Ethereum is a necessary evil
All miners must evaluate all transactions limit computation cost
All miners must store all state limit storage use
Short-cut the halting problem
Finite GAS_LIMIT ensures all programs halt
Bitcoin also employs a (crude) means to pay for resources consumed
Every operation has a fixed gas cost
Basic operations
ADD, MUL, PUSH, JUMP
Storage read
Storage write
Storage write (from zero)
Storage zeroize
Contract call
CALL, CODECALL, etc.
Transaction overhead
Contract creation
Contract destruction
SELFDESTRUCT
Gas metering is complex
1. Transactions specify START_GAS, GAS_PRICE
2. If START_GAS GAS_PRICE > caller.balance, halt
3. Deduct START_GAS GAS_PRICE from caller.balance
4. Set GAS = START_GAS
5. Run code, deducting from GAS
6. For negative values, add to GAS_REFUND
a. GAS only decreases
7. After termination, add GAS + GAS_REFUND to caller.balance
Every step taken by a contract costs gas Gas remaining
PUSH1 0x80
PUSH1 0x40
PUSH1 0x04
CALLDATASIZE
PUSH2 0x011c
PUSH4 0xffffffff
Every step taken by a contract costs gas Gas remaining
PUSH1 0x80
PUSH1 0x40
PUSH1 0x04
CALLDATASIZE
PUSH2 0x011c
PUSH4 0xffffffff
Every step taken by a contract costs gas Gas remaining
PUSH1 0x80
PUSH1 0x40
PUSH1 0x04
CALLDATASIZE
PUSH2 0x011c
PUSH4 0xffffffff
Every step taken by a contract costs gas Gas remaining
PUSH1 0x80
PUSH1 0x40
PUSH1 0x04
CALLDATASIZE
PUSH2 0x011c
PUSH4 0xffffffff
Every step taken by a contract costs gas Gas remaining
PUSH1 0x80
PUSH1 0x40
PUSH1 0x04
CALLDATASIZE
PUSH2 0x011c
PUSH4 0xffffffff
Every step taken by a contract costs gas
PUSH1 0x80
PUSH1 0x40
PUSH1 0x04
Gas remaining
CALLDATASIZE
Remaining gas is
refunded to the transaction creator
PUSH2 0x011c
PUSH4 0xffffffff
Gas must be paid upfront by transaction creator
Maximum amount of gas this transaction can consume
Amount (in wei) sender is willing to pay per unit of gas
The full gas picture
C.foo() alice.balance
PUSH1 0x80
PUSH1 0x40
PUSH1 0x00
Id like to execute C.foo() with
PUSH1 0x40
START_GAS = 100000 at a
GAS_PRICE of 2
The full gas picture
C.foo() alice.balance
Gas remaining
Gas refund
PUSH1 0x80
PUSH1 0x40
PUSH1 0x00
PUSH1 0x40
The full gas picture
C.foo() alice.balance
Gas remaining
Gas refund
PUSH1 0x80
PUSH1 0x40
PUSH1 0x00
PUSH1 0x40
The full gas picture
C.foo() alice.balance
Gas remaining
Gas refund
PUSH1 0x80
PUSH1 0x40
PUSH1 0x00
PUSH1 0x40
The full gas picture
C.foo() alice.balance
Gas remaining
Gas refund
PUSH1 0x80
PUSH1 0x40
PUSH1 0x00
PUSH1 0x40
The full gas picture
C.foo() alice.balance
Gas remaining
Gas refund
PUSH1 0x80
PUSH1 0x40
Total refund:
PUSH1 0x00
(74988+15000) 2 PUSH1 0x40
The full gas picture
C.foo() alice.balance
PUSH1 0x80
PUSH1 0x40
PUSH1 0x00
PUSH1 0x40
Out-of-gas exceptions are bad news
State reverts to previous value
Except that START_GAS * GAS_PRICE is still deducted
Out-of-gas errors can cascade
90 function b(): y = C.c()
return Hello
function a():
return x + World!
80 function c(): while (true) {
return Bonjour
Out of gas
Out of gas
Out of gas
Callers can choose to limit how much gas they send
function b(): 5 assert msg.gas >= 10 y = C.c.gas(5)()
assert(y == 0);
// out of gas
return Hello
function a(): 10 assert(msg.gas >= 100);
x = B.b.gas(10)()
return x + World!
function c():
assert(msg.gas >= 5
while (true) {
return Bonjour
Hello World!
Out of gas
Contracts can query the amount of gas remaining
contract HelloWorld {
function bar(address a) public returns (int){
if (gasleft() > 50000)
f = new Foo();
Also available:
f = Foo(a); tx.gasprice
block.gaslimit return f.baz();
msg.gas, equivalent to gasleft() }
Gas today is about 5510-9 ether = 0.000184 USD
Gas today is about 5510-9 ether = 0.000185 USD
USD cost [April 2022]
Basic operations
ADD, MUL, PUSH, JUMP
Storage read
Storage write
Storage write (from zero)
Storage zeroize
Contract call
CALL, CODECALL, etc.
Transaction overhead
Contract creation
Contract destruction
SELFDESTRUCT
Economics of gas are similar to transaction fees
Miners choose transactions based on GAS_PRICE
In theory, they should not care which opcodes are used
In practice, some overpriced opcodes may be preferred
Maximum gas limit per block
Miners can slowly raise it, each block votes
Miners may include the most profitable transactions
source: ethgasstation.info
Miners limited by a global limit on gas per block
Arbitrage possible with fluctuating gas prices
Idea: bank gas when prices are low
Store junk in memory
Create junk contracts
Free these resources when prices are high
Saves if gas costs increase by 33% or more
Summary: smart contracts must optimize gas usage Running time, memory consumption irrelevant
Compilers should optimize for gas
Programmers should optimize, too
Tip: avoid storage if at all possible!
Ethereum project
Ethereum blockchain is different than Bitcoins
Target time between blocks
14.5 seconds
10 minutes
Proof of work
Stale block rewards
Uncle rewards
Hard forks
regularly planned
explicit (committed in each block)
Ethereum is run by the Ethereum Foundation
Compatible alt-clients exist (e.g. Parity, Consensys)
Hard Forks are frequent in still lags behind Bitcoin
CS: assignmentchef QQ: 1823890830 Email: [email protected]
Reviews
There are no reviews yet.