<= THIS
Node1 sends TX1
Node2 relays it
Node1 sends TX1
Miner includes it in a block.
Node2 relays it
Node1 sends TX1
Node2 DECIDES to relay it
Miner DECIDES to include it in a block.
Transaction:
nonce : u256
gas_price : u256
gas : u256
to | null : h160 (address)
value : u256
data : bytes
v : u64
r : u256
s : u256
Transactions in the network are encoded using RLP in this exact order (9 fields)
Transaction:
nonce : u256
gas_price : u256
gas : u256
to | null : h160 (address)
value : u256
data : bytes
v : u64
r : u256
s : u256
A rational miner will try to maximise her's earnings.
So let's just order by fee: gas_price * gas
Note: Miner strategy is not part of the protocol!
But processing transaction takes time and it increases a chance to mine an uncle.
There is an equilibrium:
https://blog.ethereum.org/2016/10/31/uncle-rate-transaction-fee-analysis/
https://etherchain.org/statistics/gasPrice
Do you remember about nonce?
We must include transactions in order, despite the fee!
// We're ordering by "nonce height" first
Height=0:
Tx1(from=1, fee=3, nonce=0)
Tx3(from=2, fee=1, nonce=100)
Height=1:
Tx4(from=2, fee=2, nonce=101)
Tx2(from=1, fee=4, nonce=1)
The transactions may be received out of order.
What to do if we get a transaction with nonce=N+1 before none=N?
We cannot ignore them, cause they might never be propagated again.
We maintain two separate queues:
"current" and "future"
// Current
Height=0:
Tx1(from=1, fee=3, nonce=0)
Tx3(from=2, fee=1, nonce=100)
Height=1:
Tx4(from=2, fee=2, nonce=101)
Tx2(from=1, fee=4, nonce=1)
// Future
Height=3:
// awaiting tx with nonce=2
Tx5(from=1, fee=3, nonce=3)
Of course both queues should be limited.
(especially future queue)
Shall we have a gas price market?
Whitelisting contracts the users may invoke
(e.g. faucet contract).
We also need to validate correctness of the transaction.
What if the transaction uses more gas than declared?
But we do verify minimal gas requirements:
21k + costOf(data)
We also need to check if user has enough balance.
// A has 5 ETH
Height=0:
Tx1(from=1, to=B, value=5)
Height=1:
Tx2(from=1, to=C, value=5)
But you cannot tell if the first one doesn't increase the balance without executing it!
What if someones sends two transactions with the same nonce?
// Fee is the same. Which one should we choose?
Tx1(from=A, nonce=0, gasPrice=1, gas=100) fee = 100
Tx2(from=A, nonce=0, gasPrice=2, gas=50) fee = 100
So how to "cancel" the transaction?
The transaction might become stalled and block subsequent transactions.
So how to "cancel" the transaction?
You can *try* to replace transaction with no-op transactions and increase gas price.
Transaction:
from: A,
to: A,
value: 0,
gas: 21k,
gasPrice: ?,
--relay-set (cheap, strict)
--usd-per-tx
--tx-gas-limit
--refuse-service-transactions
Next stage of the Etherum project.
Currently:
nonce
gas_price
gas
to | null
value
data
v
r
s
Metropolis:
gas
to | null
data
network_id
# Get signature from tx data
sig_v = ~calldataload(0)
sig_r = ~calldataload(32)
sig_s = ~calldataload(64)
# Get tx arguments
tx_nonce = ~calldataload(96)
tx_to = ~calldataload(128)
tx_value = ~calldataload(160)
tx_gasprice = ~calldataload(192)
tx_data = string(~calldatasize() - 224)
~calldataload(tx_data, 224, ~calldatasize())
# Get signing hash
signing_data = string(~calldatasize() - 64)
~mstore(signing_data, tx.startgas)
~calldataload(signing_data + 32, 96, ~calldatasize() - 96)
signing_hash = sha3(signing_data:str)
# Perform usual checks
prev_nonce = ~sload(-1)
assert tx_nonce == prev_nonce + 1
assert self.balance >= tx_value + tx_gasprice * tx.startgas
assert ~ecrecover(signing_hash, sig_v, sig_r, sig_s) == <pubkey hash here>
# Update nonce
~sstore(-1, prev_nonce + 1)
# Pay for gas
~send(MINER_CONTRACT, tx_gasprice * tx.startgas)
# Make the main call
~call(msg.gas - 50000, tx_to, tx_value, tx_data, len(tx_data), 0, 0)
# Get remaining gas payments back
~call(20000, MINER_CONTRACT, 0, [msg.gas], 32, 0, 0)
Current miner strategy doesn't work at all!
Ideas:
We can also try to execute the transaction with some reasonable gas limit and check if you will get payed.
Problem: What if the state is reverted after that?