1 of 18

Scalability and Asynchronous Programming

Ethereum 2.0… now processing 100,000 towers of ugly javascript callback code per second!

2 of 18

Ethereum right now

  • Every node processes every transaction
  • Every node stores all of the state
  • Sloooowwwww….
    • And, unlike nearly all other systems, does NOT get more powerful the more nodes join the network

3 of 18

A Vision for 2.0: Sharding

4 of 18

A Vision for 2.0: Sharding

  • State split into shards
  • Each account is in one shard
  • Accounts can only send transactions to or call accounts in the same shard

5 of 18

The Bottom Level

6 of 18

The Bottom Level

  • Every transaction specifies a shard ID
  • A transaction “in” shard X implies that it sends from and to an account in shard X
  • A transaction grouping in shard X contains zero or more transactions in shard X
  • Specifies pre-state root and post-state root for that shard

7 of 18

The Top Level

8 of 18

The Top Level

  • Think of the top-level as a non-scalable, Ethereum 1.0-style, blockchain, with a funny state transition function
  • Tx is valid if:
    • Pre-state root equals shard root in global state
    • Signatures (⅔ of a randomly pre-selected set of 135) are valid
  • Shard root in global state becomes post-state root

9 of 18

Async Transactions

  • Q: how do we do cross-shard transactions?
  • Problem: if we allow cross-shard calling, then parallelization becomes impossible

10 of 18

Solution: Merkle tree receipts

11 of 18

Step 1: The Call

def registerName(currencyShard, currencyAddress, name, fee):

self.next_cbid += 1

log(type=CallReceipt, {

shard: currencyShard, to: currencyAddress,

method: withdraw, args: {

from: msg.sender, to: self, value: fee,

}

cbid: self.next_cbid, callbackMethod: withdrawCallback

})

self.cbArgs[self.next_cbid] = {

name: name, owner: msg.sender,

shard: currencyShard, to: currencyAddress

}

12 of 18

Step 2: The Other Side

def submitLog(logProof):

if verify(logProof, block.prevStateRoot) and

not self.spent[logProof.log.cbid] and

log.shard == myShard and log.to == self:

self.spent[logProof.log.cbid] = true

o = self.call(method=log.method,

sender=log.sender,

senderShard=log.senderShard, **log.args)

log(type=CallReceipt, {

response: o, shard: log.senderShard, to: log.sender,

method: log.callbackMethod, args: { response: o },

cbid: logProof.log.cbid

})

13 of 18

Step 3: Callback

def submitCallback(logProof):

cbid = logProof.log.cbid

if log.sender == self.cbArgs[cbid].to and

log.senderShard == self.cbArgs[cbid].shard and

verify(logProof, block.prevStateRoot) and

not self.spent[cbid]:

self.spent[cbid] = true

self.call(method=log.method,

**self.cbArgs[cbid], **log.args)

def withdrawCallback(name, owner, response):

if response is true:

self.domains[name].owner = owner

14 of 18

Asynchrony in Practice

  • Three main use cases for cross-contract calling
    • Get information
    • Send an action without response (eg. transfer funds)
    • Send an action with a response (eg. withdraw funds + success/failure)
  • The second is not problematic at all, the first and third can be

15 of 18

Problems and solutions

  • Race conditions
    • Mutual exclusion locks
  • Async programming is hard
    • Javascript-style callbacks
    • Promises
    • async.map, etc

16 of 18

The economics

  • In a scalable model, contract-to-contract calling requires actual transactions, not just virtual messages
  • This can be made censorship-resistant: there is common knowledge that info to create sub-calls exists, so sub-calling can be compelled
  • Incentivization for sub-calls?

17 of 18

The economics

  • Transactions pay fees to group creators, group creators pay fees to blockmakers
  • Incentives still fine: blockmakers want to include highest-fee-paying groups, group creators want to include as much as possible both for own benefit and to get as high fees as possible
    • Maybe anti-spam PoW is required on groups?

18 of 18

More generality

  • First k bits of an address is a shard ID
  • Every transaction (and every transaction group sets its own k)
  • Attempting to synchronously call a contract outside of a shard triggers an OOG-like exception
  • Transaction groups on all k have same gas limit
    • Gas price proportional to 2-k in equilibrium