# FAQ for using virtual machines in the blockchain
## Preface
This document is formed as an FAQ for the new blockchain architect and implementer,
documenting possible contract runtime design decisions and the logic behind them.
In some cases it’s really an answer, and in some others - musings on possible ways
of thinking about the problem.
## Higher level architectural questions
### Should I use a special purpose virtual machine best suited for my blockchain, or rely on the general purpose VM?
First blockchains, such as Bitcoin and Ethereum 1.0, were in favour of the
special purpose VMs, while more recent blockchains, partially due to broader
Wasm implementations availability tend to use general purpose VM,
providing blockchain APIs as external/host functions.
Advantage of general purpose VM is mostly due to the broader developers community
behind such VMs, and wider availability of the development tools, such as language
compilers, debuggers, static analyzers, IDEs, etc.
### How do I make blockchain implementation economically sustainable?
Due to the decentralized nature of the blockchain, users shall be motivated
to lend their computational resources to others. The widely accepted approach here is
to rely on gas, the financial equivalent of computation cost,
whenever computation is performed. Gas can be bought using blockchain tokens
and is spent per used computational resources. Unfortunately, it is not possible
to estimate the amount of the computational cost that the contract can incur without
executing it, due to the halting problem. This means that the user must have an
upper bound estimate on how much gas they are willing to spend that they would
declare in the transaction. This makes performing general computations on the
blockchain harder to reason about, as developers must estimate maximum computational
requirements of the contract before its execution.
### What gas is supposed to represent? Complexity of computations performed, hardware resources used, power consumed, something else?
Most practical blockchains make gas represent the number of the raw VM instructions
executed for managed code execution, and some synthetic and usually precomputed cost
for external native functions executed by the blockchain runtime. For example, the
number of actual machine instructions could be used as gas metrics for host functions.
Some blockchains however, approximate the gas as the elapsed time.
### What does the gas price reflect? How should I price the gas in my system? Pure price of hardware for validators or some economic meaning?
Gas price can either represent the cost of hardware maintenance for validators,
probably with some multiplier to make validation economically attractive,
or be used as a mechanism for improving blockchain functioning, i.e. load
balancing and attracting new users (i.e. validators could agree to work below
margin for some time to attract developers and users).
### How will my developers know the amount of gas to attach to their contract?
Prediction of the gas amount to be attached to the complex contract may become a
non-trivial problem, if execution has unbound loops. A proper gas metering better
be assisted by the developers tools.
### Can gas metering have theoretical limitations wrt impact on execution performance?
Gas metering, being computation itself, has its cost. There are few options, such as
hardware assisted gas metering, or fully precomputed gas cost if the contract execution
path is fully predictable, but in general case it’s rather hard to make it free for
the system.
### Why is gas metering not part of the Wasm standard? What shall be done with external/host functions then?
It probably shall be, and we as the blockchain community shall push forward adding gas
metering to the Wasm standard. Gas costs for the external functions likely to be part
of the Wasm runtime embedding mechanism, actual prices to be defined empirically,
unless there's a better mechanism provided by the OS/hardware.
### Shall gas be one scalar quantity, or vector (i.e. for CPU, memory, disk, network resources)?
There’s no definitive answer to this question yet, however, complex gas metering/pricing
strategies would make development experience even more complex, as one has to estimate
not one quantity, but the whole vector, and the token cost of different vector
components need to be decided as well.
### How consumed gas shall depend on the consumed resources?
The most straightforward approach is the linear dependency, i.e. program with twice
as many executed instructions shall consume twice as much gas, however nonlinear
dependencies, such as quadratic or even exponential, may be of interest in scenarios,
when too extensive computations in the contract may affect performance or stability
of the blockchain.
## Practical aspects of the execution engines
### Shall I use an interpreter, non-optimizing JIT, optimizing JIT, non-optimizing AOT, optimizing AOT compiler in my blockchain?
The answer depends on the required features, and the following table will try to help.
Every solution is subjectively measured on a bad/ok/good/great scale.
| correctness | great | good | ok | good | ok |
| performance | bad | ok | good | ok | great |
| security | great | ok | bad | ok | bad |
| additional per-contract storage | great | great | great | bad | ok |
| additional per-contract computations | great | ok | bad | good | good |
| Gas counting in VM | great | ok | mostly ok | ok | mostly ok |
With an optimizing compiler, it’s possible to have decent performance, at the cost of spending
more time in the runtime in case of JIT, or more storage and compilation time on execution
of the contract first time in case of AOT compilers. Another potential limitation of optimizing
compilers is the possibility of JIT bombs and other security vulnerabilities coming from running
such complex pieces of software as optimizing compilers on the untrusted input. However,
with the careful selection of optimization passes and VM implementation it shall be possible
to limit the security impact while keeping decent performance.
### How do I do gas metering in presence of the compiler?
In case of JITs execution of the compiler can be either ignored, metered based on input size with
fixed coefficient, or metered precisely. In the latter case, JIT bombing is less of the problem,
as JIT bombs presumably will be prohibitively expensive. However, metering the compiler requires
cooperation from its authors, or ability to run the compiler itself in a metered environment
(i.e. if JIT is executed in VM itself). In case of AOT compilers, compilation is once per contract,
and technically compilation cost here could be included into the cost of contract deployment.
### What are the dangers of bugs in compilers/VMs?
Unlike traditional software development, bugs and UB in the contract runtime could be pretty
devastating for the network coherence, as they may trigger inconsistency between nodes, and
lead to undesired blockchain forks. Thus, whenever there’s a risk of behavioral discrepancy
between nodes executing contract code - it shall be mitigated. No visible state shall rely
upon timing taken for the certain operation, compilation or execution alike, and if an
execution correctness problem exists - it must be the same on all nodes.
Thus compiler crashes are always preferred to potential hiding of undefined behavior.
Another even more dangerous scenario of a compiler bug is when the bug is consistent for
all nodes, but it leads to incorrect or vulnerable contract execution. In that case the bug
can go unnoticed for many months until it manifests or gets exploited by someone.
### What is the cold cache attack and how do I avoid it?
Cold cache attack is a generic attack not specific to the contract runtime.
Consider the following scenario. Suppose some blockchain has the full governance mechanism that
allows participants to decide on the configuration parameters of the system. Suppose someone
discovered that the node would consume less resources if they add a caching layer somewhere, e.g.
if they decide to cache compilation of the contracts. Suppose everyone incorporates this change
into their nodes, then through the governance mechanism they lower the fee of the cached operation,
to represent the average cost of executing it. But average cost does not represent the worst case
scenario. So someone might find a way to execute computation on the system in such a way that they
would miss the cache. In case of the compiled contract this could be executing a “cold” contract.
As a result they will incur high computational cost to the system by paying for an average
scenario. This could lead to the node slowdown, dropout of the participants, etc.
There is currently no clear way how to avoid cold cache attack for the case when we cache contract
compilation.
### What contracts can be executed without the actual blockchain? How to automatically test contracts?
Contracts are state machines, transferring the input state to the output state, so it’s not
required to have the traditional blockchain notions, such as network consensus and global
transaction history to be present to just execute the contract on known state. Thus, running
certain contracts, such as tests, in predefined blockchain state is an extremely desirable feature
of the contract runtime. It is also useful to dry-run contracts inside the devtools, e.g. to
estimate the gas usage.
### Can Wasm clients be used for gas estimation?
Up to a certain extent, the pure computations part (such as compiler algorithms) is easy, when host
functions (external to Wasm functions provided by the blockchain) are involved it becomes harder.
## Development tools
### What programming languages shall I support in my blockchain?
This is a rather broad question, so some aspects of that will be covered in next questions.
The most basic dichotomy is to support the general purpose language(s) such as Rust, AssemblyScript
vs. the specialized contract language, such as Solidity, Move, etc. Supporting custom language
usually induces cost of the toolchain maintenance, and it not only includes the compiler,
but also editor support, static analyzers, IDE and so on. Another important problem is the higher
barriers for developers, since they should learn a new language, potentially with new paradigms,
and a few of online resources to learn. Using general purpose language seems preferable,
if your blockchain aims at providing rich smart contract functionality, especially if third party
libraries are expected to be used in the contract.
### What to do with the garbage collection in general purpose programming languages?
As one could see from the previous question, high level languages may require GC,
and the contract runtime may not have such a feature available. There are few options:
* Not support such a languages
* Support such languages but not implement object reclamation and GC as many contracts are short
lived it could be a viable option
* Implement automated memory management as part of the language runtime and ship it with every
program or once per language runtime version
* Use runtime with existing GC, such as JVM or JS VM
* Move forward with the [WebAssembly GC proposal]
[WebAssembly GC proposal]: https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md
### Shall I support pure functional language, such as Haskell, in contracts?
It depends on the target audience of your blockchain. Implementation wise, runtime for the
functional programming languages is not that different from runtime for an object oriented
language, and typically needs the GC. Thus, see the previous question.
### Is it important for the smart contract to be formally verifiable?
As with any other software, formal verification on smart contracts checks a certain behavioral
aspects of the program, and as such, could be a useful tool for finding bugs and potential
misbehavior of the program. However, it is not a silver bullet, and does not guarantee that the
smart contract is “correct”. Formal verification could be used as one of the static analysis tools
helping developers to write the better code.
### Is it important for the smart contract language to be Turing-complete?
There is no definitive answer to that question yet, however, for many practical aspects Turing
incompleteness means lack of the unbound loops/recursion, which limits the language expressive
and computational power. Many practical algorithms, such as Dijkstra’s algorithm or even simple
BFS/DFS are expressed in a form that is hard to formally prove to be bound, and so hard to
express in a Turing incomplete language. However, in some cases, Turing-incomplete contracts
could be useful as they are much easier statically analyzed and formally verified.
### Should my contracts use DSL or metaprogramming?
Both a Domain Specific Language (DSL) or a certain metaprogramming technique, such as the
template generator, on top of the general purpose language (such as Rust) seems to be a
good compromise between somewhat excessive expressive power of the general purpose language
and ability to use tooling (compilers, debuggers) for such a language. Exact choice of the
technology mostly depends on the underlying general purpose language. In the case of Rust,
DSL approach could be implemented using standard Rust AST macros.
### Should my embedded DSL (eDSL) be blackbox or glassbox?
Whether the eDSL shall be blackbox and not allow underlying language primitives invocation, or be
glassbox and allow the full power of the underlying general purpose language is an important design
decision. Blackbox approach produces less powerful, but more analyzable and verifiable language,
while glassbox is mostly a convenience to simplify coding, not really controlling the expressive
power of the language. See [this
question](#is-it-important-for-the-smart-contract-language-to-be-turing-complete) for further
discussion.
### Should we make it impossible to write unsafe contracts?
Dichotomy here is either taking a paternalistic approach for the users, and trying to constraint
them as much as possible through eDSL to the point where we minimize the chance of them making
some common contract-specific mipledge. Or we take a liberal approach and consider typical
contract mipledges to be under full users’ responsibility. Most of the modern blockchains
follow the latter approach, sometimes augmented with the static analysis tools to help users
avoid certain classes of mipledges.
### Who is responsible for the safety of contract execution in the blockchain?
The question of responsibility of what’s going on in a decentralized distributed system is a very
complex topic. From contract runtime point of view, it can only provide an execution environment
which behaves according to the specification, and allows chain to proceed with any contract given
as input, by either consistently executing it and modifying the ledger per contract’s execution
result or refusing execution with a sensible error message and making no changes in the ledger.
Correctness and responsibility beyond that shall be usually decided outside of the contract runtime.
### Who is responsible for the safety of the assets programming?
Blockchain runtime has an option to provide primitive for safe asset-like manipulation, however
they must be carefully designed to avoid limiting functionality, or repeating generic data
manipulation operations available in general purpose programming language by default.
### Should all contracts be optimal in terms of performance?
The most important metric of performance in the blockchain is the rate of blocks/transactions
processed by the chain as the whole, and contract runtime performance is a part of the equation,
responsible for the raw execution speed. So contract optimizations are critical only if it makes
the whole chain stall, and if performance is dominated by the other components, optimizations in
contract runtimes may be ignored. When discussing the compiled contract size, huge (>1MiB)
contracts are generally considered harmful. Shall we optimize 100KiB contracts to be as small as
possible, at the cost of worse debuggability and less applicability of the general purpose
libraries is not as clear. We generally tend to consider such optimizations worsening development
experience as excessive. Also, there are certain best practices, such as avoiding JSON and using
more efficient binary serialization for transferring parameters to contracts, which should be
communicated to the blockchain developers.
### Real financial world is asynchronous. Should DeFi (decentralized finance) also be?
While a pretty broad question, when projected on smart contract context, it means few rather simple
questions.
* Shall cross-contract calls be represented as:
* sync operations
* async operations
* continuations
* Shall some/all host functions be asynchronous?
Answers to those questions depend on the blockchain architecture, however general purpose
contract runtime likely shall support both modes of operation.
### How to think about the computational model for smart contracts, especially if they do I/O ?
The basic dichotomy here is the following: shall you expose the ability of performing callbacks
driven by the external operation in the same execution round (i.e. not recorded by the blockchain),
or all the operations performed by the smart contract must be time-bound synchronous, and all async
operations are represented as subsequent invocations of the same contract at different entry
points/states. Second approach seems to be better suitable for the practical applications, as
otherwise the contract must cope with the changed state of the blockchain during its execution,
which may be not straightforward, and the contract runtime can no longer rely on predictable/bound
execution time of the contract.
### Should there be a wasi-blockchain spec like for instance the upcoming wasi-crypto spec?
WASI per se mostly provides the interface to the system operations, like native or FFI calls,
while metering naturally accounts for resources consumed both inside and outside of the VM
during arbitrary contract execution. However, API to control metering could be handled as
a WASI operation.