Video: https://youtu.be/Cj6nOyBnQiY
Fast, Deterministic, and Verifiable Computations for Blockchains with WebAssembly
Speaker: Mike Voronov, @VMS11
Deterministic computations are essential for building open blockchain networks where any state transition needs to be verified by multiple network nodes. In the Fluence network computations generally happen off-chain but can be partially repeated on-chain in the case if a dispute over computation results is raised.
We will discuss how to achieve computational determinism for arbitrary WebAssembly programs; how to implement an on-chain dispute resolution by running a WebAssembly interpreter in an Ethereum smart contract; how to employ existing JIT technologies to achieve fast WebAssembly execution. Finally, how to efficiently merkelize virtual machine state, count spent gas, and resolve verification game disputes.
2. • Open-source, decentralized cloud computing network
• Charge developers for computational complexity only: no hash mining
• WebAssembly as the platform for fast & verifiable stateful computations
2
Objectives
5. Problems:
• nodes running the same code got different computation results
• nodes got same results but claim to have spent different amounts of gas
Solutions:
• consensus algorithms, ZK proofs, hardware enclaves
• we use verification game (a part of a special kind of consensus)
5
Verifiable computations
6. • Verifier finds an incorrect state transition and opens a dispute on Ethereum
• Verification game narrows the dispute to a single WebAssembly instruction
• Ethereum smart contract repeats the instruction and penalizes the bad node
6
Verification game
7. Execution mode: fast execution
• JIT/AOT compilation is essentially mandatory
• Only final state (VM memory) matters
Dispute mode: granular execution
• JIT/AOT compilation is highly desirable
• Intermediate states (VM memory, stack, instruction pointer) matter too
• Ability to take & load VM snapshots, stop at k-th instruction
• Ability to extract the data needed to execute single instruction on Ethereum
7
Execution duality
9. • Each Wasm module is compiled to JVM class by Asmble
• Both JVM and Wasm are stack-based VMs => straightforward conversion
9
WebAssembly to JVM bytecode
14. 14
Dispute resolution: k-ary search
• Need to record in Ethereum virtual machine state on every search step
• Need to find the instruction which was executed differently:
😇 VMp–1 = 👿 VMp–1
😇 VMp ≠ 👿 VMp
• Then, need to send this instruction along with required data to Ethereum
15. 15
Virtual machine state
Need to track:
• memory
• stack
• globals
• instruction pointer (ip)
• executed instructions counter (eic)
• used gas
16. Need to collapse all the required data into a single record
Need to generate proofs for:
• memory chunks and stack frames
• instruction pointer and executed instructions counter
• used gas
HVM = hash(Hmem, Hstack, Hip, Heic, Hgas)
Hmem = merkle(memory)
...
Hgas = hash(gas)
16
VM state hash
17. Standard Merkle hash:
• needs to rehash the entire memory region
even if only a single byte was changed
• is not optimal for multiple computations
during k-ary search
• is not optimal for large-scale state updated
by simple request processing code
17
Linear memory hash
18. Idea:
• track memory chunks that were made dirty
during the state transition VMi => VMi+1
• once the state transition is complete, all
chunks are clean again
• store a cache of intermediate hashes in the
Merkle tree
• when requested, recompute hashes
(including Merkle root) on dirty paths only
18
Incremental memory hash
19. Algorithmic complexity:
• need to recompute the dirty chunk hash
• need to recompute all hashes on the dirty path
O(chunk_size + hash_size * log(total_chunks))
Additional memory usage:
• dirty chunks bitmap index: 1 MB
• tree hashes cache: 2 * 32 * 10242 = 64 MB
19
Incremental hash: complexity
memory = 4 GB, chunk = 4 KB, hash = 32 B
20. 20
Attack: malicious code updates 1 byte in each memory chunk
How much should we charge? The node had to rehash the
entire 4 GB memory, but the code has written just 1 MB.
Solution: charge fixed price for each chunk that was dirtied
algorithms taking into account page caching should not be hurt too much
Incremental hash: gas usage
21. Normally, WebAssembly stack is implicitly supported by the JVM stack
However, there is no easy way to access JVM stack data
Stack emulation can be used to retrieve values from the WebAssembly stack
21
Shadow stack
24. Bottomline
Computation machine has execution duality:
Normal mode:
- EIC
- gas
- merkle hash of the final state
Dispute mode:
- EIC
- gas
- merkle hash of the final state
- shadow stack
24
26. • External function calls
• VM resource exhaustion
• NaN floating point payloads
https://dl.acm.org/citation.cfm?doid=3062341.3062363
26
Non-determinism sources in Wasm
27. Our approach:
• at now, on the testnet imports from
the host environment are not allowed
• to obtain persistence, WebAssembly
memory is backed to disk by the host
system
27
External function calls
We are working on supporting of a subset of the WASI syscalls:
for example – time, filesystem, random number generation operations
28. Our approach:
• developer configures desired memory and stack size
• allocation of all dynamic Wasm parts (heap, stack, table) is performed
at the virtual machine initialization
• grow_memory always returns –1
28
VM resource exhaustion
29. NaN (not-a-number) – is a special type of a floating-point value
29
NaN payloads
30. Popular platforms have different behavior regarding NaNs
New NaN value:
• x86 – NaN with the sign bit set
• ARM and others – produce with it unset
Operations with multiple NaN inputs:
• x86 – first NaN input
• ARMv8 – NaN depending on the signaling and quiet state
some hardware architectures prefer to return a NaN with a fixed bit pattern 30
NaN payloads
32. 32
NaN payloads
Idea: instrument all floating-point operations – convert non-canonical NaNs
into canonical NaNs
Better idea: instrument only those operations that transfer floating-point
values outside of the floating-point domain
Outside transfer operations:
• {f32,f64}.reinterpret_{i32,i64} – converts float value to integer
• {f32,f64}.store – stores float value to the linear memory
• copysign – copies the sign bit into a non-NaN value
33. Bottomline
To obtain deterministic WebAssembly execution, we:
• block syscalls (in the future: provide a subset of deterministic syscalls)
• preallocate all dynamic resources
• use the canonical NaN pattern when transferring floats outside
33
35. 35
Fluence: hybrid security approach
Speed layer
On-demand database (Redis/SQLite) clusters
Security layer
DB transaction history validation for
the entire network
Data availability layer
DB transaction history storage in Swarm/Filecoin
Dispute resolution layer
Verification game with Ethereum as the final judge
36. Speed layer
• Ethereum holds the registry of deployed databases
• Consensus-based (BFT) replication between nodes
• Direct frontend <–> database interaction
• TX history is uploaded to Swarm/Filecoin
Tendermint
WebAssembly
36
37. Security layer
Composition:
• TX history is verified segment by segment
• Segments are sequentially verified by several validators
Validators:
• Are randomly selected from the shared network pool
• Verify that preceding validations were autonomous
• Do not know if there will be a subsequent validation
37