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) 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.
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.
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:
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;}
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();}}}
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.
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:
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.
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.
The core of the V8VM architecture is VMManger, which has the following three functions:
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:
Mainly for contract development and winding, there are two main functions:
For the real implementation of the chain contract, there are two main functions:
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.
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:
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.
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)}}}
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
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) )
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}
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.