paint-brush
How We’re Designing a Better Virtual Machine than Ethereum and EOSby@Kevin_Tan
3,247 reads
3,247 reads

How We’re Designing a Better Virtual Machine than Ethereum and EOS

by Kevin TanSeptember 30th, 2018
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

<strong>Written by Li Haifeng — </strong><a href="https://iost.io/" target="_blank">IOST</a> Senior Engineer

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coins Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - How We’re Designing a Better Virtual Machine than Ethereum and EOS
Kevin Tan HackerNoon profile picture

Written by Li Haifeng —IOST Senior Engineer

Former Tencent senior engineer and successful entrepreneur. Responsible for leading the restructuring of Tencent News and Tiantian Express which achieved over 150 million daily visitors. Lead engineer for IOST’s virtual machine.

The importance of virtual machine design and performance — as well as smart contract capabilities — has been recognized by all blockchain developers as being crucial for successful mainstream DApp adoption. As a result, the implementation of these core features has become the main focus for competition and differentiation between major public blockchain networks. It is these implementations that may determine which network will be successful and ultimately, which will win the battle for real world adoption and user growth.

Last week IOST released the second iteration of our test network to the public — Everest v1.0. Alongside supporting smart contract programming with JavaScript, a smart contact Domain Name System (DNS) and Multiversion Concurrency Control (MVCC), this update also included the deployment of our new Virtual Machine based on the V8 engine.

In the following technical article, I analyze and critique Ethereum and EOS in regards to their virtual machine development as well as giving an overview of IOST’s implementation and design choices that specifically address several of the issues facing our competitor’s networks.

The Ethereum Virtual Machine (EVM)

The Ethereum Virtual Machine (EVM) is a “quasi-turing complete” 256-bit virtual machine, one of the most important and integral components of the Ethereum network.

As EVM smart contract development has gradually improved, there has been ever increasing sophistication to the DApp applications — such as the recently popular Fomo3D game — launched on the network.

With this progression however, there are several barriers and issues restricting Ethereum DApp development which is ultimately hindering functionality and long term potential for this network.

Firstly, the Ethereum virtual machine (EVM) is not Turing complete

There is currently a common misconception that the Ethereum virtual machine is Turing-complete, however this is not the case.

Turing completeness means that any computable problem can be solved. The essence of a programming language or virtual machine is a Turing machine. If a programming language or virtual machine is Turing-complete, it means that it can do all the things that Turing can do, that is, it can solve all the computational problems without exception.

In the design of the Ethereum virtual machine, since the calculation of the instruction is constrained by gas, this limits the number of calculations that can be completed. This is a common cause of Turing incompleteness, because the loop, recursion, or computational bounds cause the program to terminate, so applications running on the EVM are subject to many restrictions therefore making the EVM not Turing-complete.

Secondly, the design of EVM is irrational

As development of DApps using smart contracts has increased, some of the flaws of the original design of the EVM have gradually emerged, with some of these leading to serious security concerns. On the Ethereum virtual machine, we believe that there are the following issues in the design and security levels:

1. Smart contract design level

  • EVM lacks complete standard library support. Even the most basic string type support, which is very hard in EVM, such as string splicing, cutting, searching, etc — all need to be implemented by developers themselves. At the same time, the self-implemented class library may be too high in time and space complexity, resulting in consumption of a lot of unnecessary gas. Alternatively, the developer can borrow relevant class library code from the open source project itself, but this again will introduce more security issues and add to the complexity of contract code auditing which would make the process highly inefficient.
  • DApps are difficult to debug and test. In addition to throwing OutOfGas exceptions, EVM does not return any information to the developer. It is impossible to print logs, make breakpoints, and single-step debugging. Although the event mechanism can partially improve the problem, the design of the event mechanism itself determines that it is not an elegant and easy to use debugging tool.
  • Floating point numbers are not supported. Ethereum uses Wei as the smallest unit. Wei only has integers and does not support other granular measurements. This design creates a precision problem caused by the introduction of floating point numbers. In order to represent an ETH variable, there will be a lot of zeros after the variable, which makes the code maintenance extremely complicated. At the same time, it is undeniable that floating-point numbers still have great value in certain scenarios, and they cannot be abandoned completely.
  • Contracts cannot be upgraded. Contract upgrades are a strong requirement in smart contract development. This is an issue that every contract developer must consider for their project. Contract upgrades can implement security patches for existing deployments as well as extend their usability, features and more. EVM does not support upgrades at all — which as a result means developers can only solve this problem by issuing new contracts — which is time consuming, costly and laborious.

2. Smart contract security level

  • Overflow attack concerns. EVM’s safeMath library is not used by default. For example, when the developer calculates the solidity uint256 — if the final result is greater than the maximum value of uint256 — the overflow will be changed to a small number therefore creating an overflow vulnerability. Tokens such as BEC and SMT have suffered from overflow attacks, which have brought extremely serious consequences. An example of the overflow vulnerability in BEC is as follows:






function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {uint cnt = _receivers.length;uint256 amount = uint256(cnt) * _value; // overflow occurred hererequire(cnt > 0 && cnt <= 20);require(_value > 0 && balances[msg.sender] >= amount);// require is always established after overflow, generating a vulnerability







balances[msg.sender] = balances[msg.sender].sub(amount);for (uint i = 0; i < cnt; i++) {balances[_receivers[i]] = balances[_receivers[i]].add(_value);Transfer(msg.sender, _receivers[i], _value);}return true;}

  • Re-entry attacks. A major feature of solidity is that you can call other external contracts, but when you send ETH to an external address or call an external contract, you need to submit an external call. If the external address is a malicious contract, the attacker can add malicious code to the fallback function. When this transfer then occurs, the fallback function is called to execute the malicious code. The malicious code executes the vulnerable function of the calling contract, causing the transfer to be resubmitted. The most serious re-entry attack occurred in the early days of Ethereum, the well-known DAO vulnerability. The following contract segment specifically demonstrates the re-entry attack:




















contract weakContract {mapping (address => uint) public balances;function withdraw() {// Transfer the caller's balance out and set the caller's balance map to 0//As long as the un-executed balance map is set to 0, you can always call msg.sender to transfer funds, and reenter here.if (!msg.sender.call.value(balances[msg.sender])()) {throw;}balances[msg.sender] = 0;}}contract attack{weakContract public weak;// This is a fallback function. It will be triggered when an external call is transferred. It will always trigger the withdraw method of weak Contract to perform a re-entrant attack.function () payable {if (weak.balance >= msg.value) {weak.withdraw();}}}

  • Unexpected function executions. EVM does not strictly check function calls, and if the contract address is controllable as an incoming parameter, it may cause unexpected behavior as follows:








contract A {function withdraw(uint) returns (uint);}// When executing contract B, it will only check if contract A has a withdraw method, and if so, the contract will be called normally.// If the transferred parameter does not have the withdraw method, A's Fallback function will not be called, resulting in unexpected behaviorcontract B {function put(A a){ a.withdraw(42);}

In summary, EVM has several problems in design and security. Although the EVM team has developed a new contract development language — Vyper — it is still in the experimental stage and currently cannot be used. Currently, when Ethereum is used on a large scale, the accumulation of these security and design issues will ultimately lead to serious vulnerabilities for the network and its users.

The EOS Virtual Machine

EOS is another high profile blockchain application recently launched and following in Ethereum’s footsteps. It has its own set of intelligent contract engines based on WebAssembly. However, there are several obvious problems in EOS’s contract development:

  • The account system is not easily accessible. EOS requires an existing account to create a new account, and only after creating an account, can a contract then be issued. Requiring a friend or third party with an EOS account is a poor solution and creates a barrier to the accessibility of this network. To create an account without a referral, you need to first purchase RAM, creating another financial barrier. After creating an account, you need to stake EOS in exchange for CPU usage time and net bandwidth to operate on the EOS network. These requirements are too convoluted and cumbersome for potential developers.
  • RAM is expensive. Unlike bandwidth and CPU, there is no fixed exchange rate for RAM on the EOS network. Developers are exposed to the exchange rate risk between RAM and EOS and generally will not receive back the same amount of tokens they have staked. This also creates an issue of RAM “trading” — creating a opportunity for speculation which in turn removes predictability of cost for developers.
  • Difficulties in development. Using C++ as a contract language greatly increases the barrier for contract development for the developer community. C++ itself is extremely complex, and it is necessary to call EOS’s C++ API to complete smart contract development. As a result, the skills and knowledge required for Dapp development on EOS network are quite extensive leading to a shrinking pool of developers who can build on this platform.

In the face of all these problems, EOS smart contract development is not very attractive to developers, and we have already seen it being one of reason for developers to abandon EOS for other projects.

The IOST Virtual Machine

At IOST, we believe that a successful virtual machine must deliver ease of use for developers, ensure robust security, as well as implement an elegant architectural design. In this respect, we aimed to solve the irrational design and security problems currently existing within EVM and EOS. After comparing the advantages and disadvantages of virtual machines such as EVM, EOS, C Lua, V8, etc., and based on the excellent performance of V8 on NodeJs and Chrome, we finally decided to build the IOST virtual machine based on V8.

IOST VMManager system architecture

The core of the V8VM architecture is VMManger, which has the following three functions:

  • VM Entrance. It interfaces external requests from other modules, including RPC requests, block validation, Tx validation, etc. The work is handed off to VMWorker after pre-processing and formatting. It gives unified entrance for all requests.
  • VMWorker lifecycle management. The number of workers (VMManager threads) are set dynamically based on system load resulting in efficient reuse. Within the workers, JavaScript hot launch and persistence of hotspot Sandbox snapshots help reduce frequent creation of VMs, and avoid heavy load in CPU and memory when the same code is loaded. This will increase the throughput of the system, allowing the IOST V8VM to achieve high performance even when processing contracts with high transaction volumes, such as fomo3D.
  • Management of interface with State Database. This ensures atomicity (prevents partial updates to the database) of each IOST transaction, denying the entire transaction when there is an error of insufficient funds. At the same time, two-level cache is achieved in the State Database before being flushed to RocksDB. This ensures less access time for different versions of data, and optimized performance for temporary data.

IOST Sandbox System Architecture

As the carrier of the final execution of the JavaScript smart contract, the IOST Sandbox completes the call to the V8VM and the next package of Chrome V8, which is divided into the Compile and Execute phases:

Compile stage

Mainly for contract development and winding, there are two main functions:

  • Contract Pack. A packaged smart contract, based on the webpack implementation, will package all the JavaScript code under the current contract project and automate the dependency installation making it possible for IOST V8VM to develop large contract projects. At the same time, IOST V8VM and Node.js module systems are fully compatible, and can seamlessly use methods such as require, module.exports and exports to give contract developers a native JavaScript development experience.
  • Contract Snapshot. With V8’s snapshot technology, IOST’s virtual machine delivers improves performance by removing the initial default empty state. Real implementation only needs to de-serialize the snapshot to complete the execution, greatly improving the loading speed and execution speed of JavaScript.

Execute stage

For the real implementation of the chain contract, there are two main functions:

  • LoadVM. To complete VM initialization, including generating Chrome V8 objects, setting system execution parameters, and importing related JavaScript class libraries, etc., thereby complete all preparations before smart contract execution. Some JavaScript class libraries are as follows:

  • Execute. The final implementation of a JavaScript smart contract on IOST V8VM will open a separate thread execution contract and monitor the current execution state. If an exception occurs, the use of resources exceeds the limit or the execution time exceeds the maximum limit, the Terminate call to end the current contract execution will be made, thus returning an exception result.

IOST V8VM performance

A virtual machine that composes the core of a public blockchain infrastructure, must deliver exceptional performance to meet the demands and requirements of the network. At the beginning of the design and virtual machine selection, IOST regarded performance as one of the most important indicators.

Chrome V8 uses JIT, inline caching, lazy loading among others to implement JavaScript interpretation. Thanks to the high performance of Chrome V8, the JavaScript execution speed of IOST V8VM has been vastly improved. After testing the performance of EVM, EOS, C Lua and V8VM in recursive Fibonacci, memory copy, and complex CPU operations we observed the following results:

These results clearly showed IOST V8VM performs well in mainstream VM implementations. The above test contains the time for the virtual machine to start and load the configuration. It can be seen that the IOST V8VM direct cold boot also has a lot of performance advantages. Later, we will also join the VM object pool, LRU cache, etc. to improve the virtual machine CPU and memory usage to better enhance IOST’s ability to handle smart contracts.

Conclusion

Currently our test network is running the first version of the IOST V8VM virtual machine. In this first version, we achieved all the intended functionality as well as verifying a lot of design concepts such as voting, contract domain name, token features, etc.. Going forward, we will continue to improve the IOST V8VM with the following main focuses:

  • Improved security across all layers and systems
  • High performance and improving faster execution of contracts
  • Ease of development and use including increasing and improving standard libraries
  • Support large project construction, debugging, and a complete tool chain

More new features will be implemented in the test network update coming in the next few weeks. We are making great progress in our ultimate goal of deploying a industry leading virtual machine that out-competes and improves upon all current available networks and are extremely excited not only about this current development, but also the entire IOST ecosystem as a whole.

Appendix: Virtual Machine Benchmark Program

EVM code

package evm



import (“math/big”“testing”






“github.com/ethereum/go-ethereum/accounts/abi/bind”“github.com/ethereum/go-ethereum/accounts/abi/bind/backends”“github.com/ethereum/go-ethereum/common”“github.com/ethereum/go-ethereum/core”“github.com/ethereum/go-ethereum/crypto”)

var bm *Benchmark


func init() {key, err := crypto.GenerateKey()





auth := bind.NewKeyedTransactor(key)gAlloc := map[common.Address]core.GenesisAccount{auth.From: {Balance: big.NewInt(1000000)},}sim := backends.NewSimulatedBackend(gAlloc)

_, _, bm, err = DeployBenchmark(auth, sim)





if err != nil {panic(err)}sim.Commit()}








func BenchmarkFibonacci(b *testing.B) {for i := 0; i < b.N; i++ {_, err := bm.Fibonacci(nil, big.NewInt(32))if err != nil {b.Fatalf(“fibonacci run error: %v\n”, err)}}}








func BenchmarkStrConcat(b *testing.B) {for i := 0; i < b.N; i++ {_, err := bm.StrConcat(nil, “This is vm benchmark, tell me who is slower”, big.NewInt(10000))if err != nil {b.Fatal(err)}}}








func BenchmarkCalculate(b *testing.B) {for i := 0; i < b.N; i++ {_, err := bm.Calculate(nil, big.NewInt(5000))if err != nil {b.Fatal(err)}}}

Lua Code





function fibonacci(number)if number == 0thenreturn 0end




if number == 1thenreturn 1end


return fibonacci(number — 1) + fibonacci(number — 2)end





function strConcat(str, cycles)local result = “”for i = 1, cycles doresult = result .. strend


return resultend





function calculate(cycles)local rs = 0for i = 0, cycles-1 dors = rs + math.pow(i, 5)end


return rsend

EOS Code



class fibonacci : public eosio::contract {public:using contract::contract;

















/// @abi actionvoid calcn(int64_t n) {int64_t r = calc(n);print(r);}int calc( int64_t n ) {if (n < 0){return -1;}if (n == 0 || n == 1){return n;}return calc(n — 1) + calc(n — 2);}};

EOSIO_ABI( fibonacci, (calcn) )



class stringadd : public eosio::contract {public:using contract::contract;














/// @abi actionvoid calcn(std::string s, int64_t cycles) {std::string ss(s.size() * cycles, ‘\0’);int32_t k = 0;for (int i = 0; i < cycles; ++i){for (int j = 0; j < s.size(); ++j){ss[k++] = s[j];}}print(ss);}};

EOSIO_ABI( stringadd, (calcn) )



class calculate : public eosio::contract {public:using contract::contract;










/// @abi actionvoid calcn(uint64_t cycles) {uint64_t rs = 0;for (uint64_t i = 0; i < cycles; ++i){rs = rs + i * i * i * i * i;}print(rs);}};

EOSIO_ABI( calculate, (calcn) )

V8 code






function fibonacci(cycles){if (cycles == 0) return 0if (cycles == 1) return 1return fibonacci(cycles — 1) + fibonacci(cycles — 2)}








function strConcat(str, cycles){let rs = ‘’for (let i = 0; i < cycles; i++) {rs += str}return rs}








function calculate(cycles){let rs = 0for (let i = 0; i < cycles; i++) {rs = rs + Math.pow(i, 3)}return rs}

About IOST

IOST is building an ultra-high TPS blockchain infrastructure to meet the security and scalability needs of a decentralized economy. Led by a team of proven founders and backed by world-class investors including Sequoia and Matrix Partners, our mission is to be the underlying architecture for the future of online services.

Horizontal expansion and high throughput is achieved through the design of the POB consensus mechanism and the second layer extension scheme. IOST provides a platform for third-party developers, entrepreneurs and businesses to realize value by improving transaction performance without sacrificing the key attributes of decentralization: privacy, open participation, and community protection from malicious attacks. IOST is more decentralized than EOS’s DPoS mechanism and is more scalable than the Ethereum smart contract platform.

IOST.io