Technical analysis: What are the differences between smart contracts on Ethereum, Bitcoin, and Bitcoin Cash?

Source: First Class

Editor's note: The original title was "Technical Analysis: Smart Contracts on Ethereum, Bitcoin, and Bitcoin Cash"

Although Ethereum is the first platform to have a Turing-complete smart contract, it is already possible to create a basic contract on Bitcoin using a language called "Script". Bitcoin Cash has been improving its smart contract functions recently. Although not as advanced as Ethereum, they all support the existence of smart contracts on the chain with their own unique methods and advantages.

This article highlights the prominent differences between smart contracts on these three platforms. Since the focus is on smart contracts and scripting functions, the basics of the platform or blockchain will not be discussed here. This article also specifically introduces on-chain smart contracts, and there are several second-tier smart contract solutions, such as RSK. These solutions are definitely worthy of discussion, as they don't do much in-depth research.

Ethereum: own state and Turing complete

Ethereum is by far the largest smart contract platform. Its smart contract is implemented using the Ethereum Virtual Machine (EVM), which is a Turing-complete virtual machine. This means that as long as there are enough resources, EVM can calculate anything. Conceptually, this is similar to many other general-purpose platforms, such as the Java Virtual Machine JVM, which are used to execute Java programs.

Explaining EVM

However, the biggest difference between those general-purpose platforms and Ethereum's EVM is that Ethereum's smart contract code is executed by all Ethereum nodes to verify the validity of the transaction. To reward nodes for executing this code, all EVM opcodes have associated gas costs, as shown in the following figure.

Figure: EVM Fee Structure

Each transaction costs a lot of Gas, depending on the opcode used. Pay the gas fee with ETH, the native cryptocurrency of Ethereum. In order to limit the amount of calculations that each block of these nodes must perform, there is a limit on the amount of Gas that can be used in a single block, called the "block Gas Limit".

During the execution of smart contract functions, the contract can store and access the necessary data. Depending on its purpose, this data can be stored in different locations, ie in different data locations . The first is the "stack" , which contains the values ​​used in the calculation. Only the first 16 items in the stack are easily accessible, so it is not suitable for long-term storage. The calculation using the stack is shown below.

Figure: Stack-based calculations

Second, to supplement the stack, " contract memory" can be used to store, retrieve, and transfer data during the current contract execution process. These values ​​can be retrieved from memory to use for calculations on the stack and store the results back into memory. These values ​​persist only during the current execution. At the end of contract execution, the contract memory and stack will be erased.

Ultimately, the location of the data is "contract storage ", which is used to persist the data during contract execution. Persistent variables (such as token balances) are stored in the contract store. To achieve data persistence, contract memory is stored on each Ethereum node. Therefore, its memory is similar to RAM, and storage is similar to a hard drive or persistent database.

More details on how the Ethereum virtual machine works can be found in MyCrypto's article.

Writing smart contracts

Although all smart contracts use EVM, most smart contracts are not written by hand using EVM bytecode, just like most JVM bytecodes are not written by hand. In contrast, there are several high-level languages ​​for writing smart contracts in Ethereum. The most popular language is Solidity. In addition to this, Vyper is also a programming language for EVM . The following figure contains an example of a very simple Solidity smart contract.

Interacting with smart contracts

Smart contracts in Ethereum exist as bytecode on the Ethereum network. This means compiling the Solidity code into bytecode and then deploying it to the network by sending a deployment transaction . This is a special transaction without any recipients, but with bytecode as transaction data.

These deployed contracts exist in the network only in the form of "fragments" of EVM bytecode, and can hardly be used alone. To "join" them, you need to provide an application binary interface (ABI) that includes a list of all common functions and their parameters. To help users learn more about these contracts, services like Etherscan help verify the contract source code so that users can check the code before using the contract.

By connecting to an Ethereum node and using its JSON-RPC interface , you can directly access all smart contracts. However, many smart contracts are accessed through front-end applications that connect to the nodes and manage the ABI. This can be done through one of many different Ethereum SDKs (such as web3.js or ethers.js), which can call JSON-RPC in the background. This provides a better experience for contract users, which is equivalent to the most difficult part being visualized.

There are two different ways to interact with smart contracts: Calls and Transactions . The call is a local call to the contract function, it does not broadcast anything to the blockchain. Therefore, the calling process is "read-only", no changes can be made to the contract status, and no fees are incurred. The transaction is a real "write operation", which will indeed be broadcast to the network and included in the blockchain, and will generate miner fees. Taking the ERC20 token as an example, the token balance is retrieved by calling, and the token is transferred by initiating a transaction.

Interoperability between smart contracts

These attributes of Ethereum (with Turing-complete EVM and persistent storage) allow the creation of any type of decentralized application that runs on the chain. A good example is the DeFi ecosystem, which includes applications such as Maker, Uniswap, and Compound, as well as the ERC20 and ERC721 token standards. These applications allow complex functions with an unlimited number of dynamic participants.

Figure: DeFi Interoperability in rDai

The most important thing is that the smart contract itself can become the "participant" of other smart contracts, thus achieving strong integration and combination between these contracts. For example, holding a token balance and lending it to Compound or a smart contract with Uniswap Exchange, or using rDai to automatically invest in DAI and contribute accrued interest to charity.

Although smart contracts can interact with each other, every transaction on the chain must come from an external account. Therefore, the interaction between Ethereum smart contracts must still be triggered by users through initial transactions. After this initial trigger, interactions between contracts are similar to direct access.

In other words, a smart contract can call the "read-only function" of other smart contracts or trigger a "write operation" (transaction). Since only external accounts can trigger transactions, transactions between smart contracts are called internal transactions or message calls to distinguish them from user-initiated transactions .

Bitcoin: stateless and simple

All Bitcoin transactions, including periodic transfers, are supported by a stack-based programming language called Script. As mentioned above, EVM of Ethereum is designed for Turing's complete and interoperable smart contracts, while Bitcoin scripts intentionally add various restrictions and work in fundamentally different ways.

Explaining the Bitcoin Script

Just like EVM, Bitcoin scripts use stacks to store values ​​and perform calculations on these values. But unlike EVM, the stack is the only data location available in a Bitcoin script . This means that it is difficult to store multiple values ​​for use in future contract executions. More importantly, this means that it is not possible to store or modify those values ​​that still exist during contract execution (but EVM can).

This is the biggest difference between Ethereum's smart contracts and Bitcoin. Ethereum's model is stateful, while Bitcoin is stateless. The popular understanding is that Ethereum can be considered similar to the ordinary imperative variable data programming paradigm, while Bitcoin is similar to the functionally unchanged data paradigm.

Bitcoin's model allows transactions to be verified independently and much more efficiently, which makes parallelization and sharding transactions easier. However, it is even more difficult to create complex smart contracts like Ethereum on Bitcoin without any variable data storage. For example, ERC20 contracts must track token balances and make changes.

In addition to these state differences, there are other factors that limit the complexity of Bitcoin smart contracts . It is worth noting that the Bitcoin script lacks support for certain arithmetic functions and any form of looping or recursion. Its contract also has a valid size limit of 520 bytes and can only contain up to 201 opcodes.

Most smart contracts on Bitcoin fall into several types of simple contracts. For example, a multi-signature contract that can be used by multiple participants, or a Hash Time Locked Contract (HTLC).

First-class warehouse knowledge: For hash locking, you can give a simple example. For example, if you buy a video from me and this video is accessed by a password, then in the transaction contract, I also changed the video access password to one of them. key, if you want to conclude a transaction, this key must let you know; once you know (you get the video), the money will be paid to me, and the entire transaction process must be completed within the set time. The contract will also trigger automatically.

And because these contracts on Bitcoin are very simple, most of the value is captured by combining different contracts with other off-chain application logic. In this way, simple contracts can be combined to create complex solutions, such as Lightning Network or cross-chain auctions.

Explaining Bitcoin transactions

Every transaction in Bitcoin is realized through the so-called "transaction output" . When these transaction outputs are available in an account, they are called unused transaction outputs (UTXOs) . These UTXOs are locked by a lock script (or scriptPubKey) and specified for use. When trying to use UTXOs, an unlock script (or ScriptSig) is provided and these scripts then perform calculations together. Transactions only take effect if the script executes without errors and the result value is TRUE.

Like EVM, all Bitcoin nodes execute these scripts to verify transactions, but the Bitcoin blockchain does not have the concept of Gas cost, so the miner is paid for each byte of transaction data. In order to limit the amount of work that nodes must complete, some restrictions have been added on some more intensive script operations.

Interacting with smart contracts

The smart contract in Bitcoin is written using the P2SH model (first-class warehouse note: there is a translation of "payment to script hash"). The lock script in P2SH mode contains a script hash, and requires a full script (called a redemption script) and an unlock script for the unlock script for that redemption script. The following figure shows this mode.

Figure: P2SH mode

First-class warehouse knowledge: P2SH mode was introduced to simplify the use of complex scripts (traditional mechanism is P2PKH). To compile a complex lock script into a simple script with a 20-byte hash, the Bitcoin address is A 20-byte public key based on Base58 encoding. The biggest difference between P2SH and traditional P2PKH methods is that the person who sets the transfer condition is changed from the sender to the receiver. By adding various transfer conditions in the redemption script, various forms of transactions can be implemented, such as multi-signature transactions.

Bitcoin nodes verify these smart contract transactions in two stages. First, hash the "redemption script" and check against the hash value in the "lock script". If they match, then use the "lock script" to unlock the "redempt script" as if the "redempt script" was the initial lock script.

Because only the hash of the bytecode is stored on the Bitcoin chain, the complete bytecode must be stored off-chain and included in any contract execution unlock script. Therefore, the "deployment" of Bitcoin smart contracts is free, but the cost of executing contracts in the future is higher. In contrast, Ethereum's initial deployment was relatively expensive, and later contract execution was cheaper.

These deployment differences encourage the comprehensive use of these two smart contracts. A good example is LocalCryptos, which supports unmanaged local transactions for Ethereum and Bitcoin. For Ethereum, it uses a large smart contract to track all transactions, and for Bitcoin, it creates a separate contract for each transaction .

Writing smart contracts

Although Ethereum has multiple high-level languages ​​that can be compiled into EVM bytecode, Bitcoin pays less attention to this. Although the systems that can be built with Bitcoin scripts are complex, the contracts themselves are usually simple. Therefore, there is almost no need to abstract the underlying system. And because the Bitcoin contract has a size limit and the high cost of each additional byte, it is important to ensure that the contract is "as small as possible" .

Although these high-level languages ​​are less important in Bitcoin, they do exist. Ivy is the "most refined" high-level language in Bitcoin , which was created by Dan Robinson in 2017. The following figure shows an example of a smart contract written in Ivy. If the recipient does not use the contract in a timely manner, the contract can be used to send money that can be recovered by the sender.

Recently, several Blockstream researchers released Miniscript, a language that focuses on the analysis and composability of smart contracts, rather than abstracting the underlying system. Considering that Bitcoin contracts often lack abstract complexity, this seems to be the right path.

Bitcoin Cash: composable features

The above is Ethereum, on the one hand, it can create many powerful and useful smart contracts. These contracts exist entirely on the Ethereum chain. At the same time, due to its stateful nature, it also raises the issue of scalability. On the other hand, Bitcoin's stateless model of smart contracts allows independent and simple verification of smart contract transactions, but its scripting system limits the usefulness of contracts.

Before the fork, Bitcoin Cash and Bitcoin had the same history, so their underlying script systems were functionally the same, and Bitcoin Cash also benefited from these same aspects. Since then, a large part of the Bitcoin Cash community has recognized the need for "more useful smart contracts." Bitcoin Cash enables new features to make its smart contracts more useful, while retaining the basic attributes that allow Bitcoin to perform stateless verification.

BCH Function Upgrade

To understand the possibility of a Bitcoin Cash smart contract, we need to look at its bi-annual network upgrade. These network upgrades will be performed each May and November since the initial hard fork of 2017. We specifically discussed changes to the Bitcoin scripting engine, although other improvements have been made, such as Schnorr signatures.

In the early days of Bitcoin, it was disabled due to the unsafe use of some opcodes. In the first year after the Bitcoin Cash fork, the developers of the Bitcoin-ABC node resolved these issues and reintroduced the opcodes with slightly modified functions, as shown in the following figure. Most importantly, this upgrade makes it possible to encode and decode structured data in a Bitcoin script.

Figure: BCH enabled new opcodes in May 2018

In the latter half of the year, another new opcode was released during the Bitcoin Cash network upgrade in November 2018. This includes the update OP_CHECKDATASIG, which enables users to verify the signature of any message in a Bitcoin script. If we combine scripting updates introduced in 2018, these updates can be used to introduce new and useful smart contract features into Bitcoin Cash.

Writing smart contracts

Compared to the original Bitcoin script, Bitcoin Cash's new features add a lot of additional complexity to its smart contracts. This makes it even more important to have an ecosystem that provides a higher level of abstraction through high-level languages, SDKs, and tools.

Two large projects currently working on this issue are Spedn (created by the pseudonym Tendo Pein) and CashScript (created by the author of this article Rosco Kalis, inspired by Ethereum's Solidity language). Although they are still under active development, these tools make it easier to process smart contracts in Bitcoin Cash. The following sections use CashScript code snippets to illustrate some features.

Oracles

When past Bitcoin script updates are grouped together, they allow you to bring external data into a smart contract for Bitcoin Cash through a trusted oracle. Structured data can be encoded as a byte array and signed by the oracle provider. The smart contract can then verify the signature and decode the structured data.

This example can be viewed in the HODLVault sample contract below. The contract enforces HODLing until a certain BCH / USD price is reached. The required BCH / USD price feed is published by the oracle provider and passed into the contract by the user. To increase decentralization, smart contracts can be set up to use multiple data sources instead of trusting a single centralized service.

Covenants

The second big use case is the technology called "Covenants", which is named after the term used in property law to restrict the use of objects. In terms of Bitcoin Cash, it limits the use of currency in smart contracts. Therefore, although smart contracts in Bitcoin can only authorize general currency spending, Bitcoin cash contracts can impose restrictions on the amount that can be spent or the identity of the payee.

When transferring Bitcoin, the sender must provide a signature to authorize the transaction. To generate this signature, the sender signs the hashed representation of the transaction. This hash is called Sighash , and the actual transaction data is contained in the Sighash preimage .

By using _OP_CHECKSIG_ and _OP_CHECKDATASIG_ with the same signature, we can access Sighash data. The data format can be checked in the specification and included in the image below. An important field is scriptCode, which contains the bytecode of the smart contract itself. The other is hashOutputs which allows the user to force the output of a transaction.

Figure: Bitcoin Cash Sighash data format

It's great to know how guaranteed contracts work at the technical level, but CashScript has abstracted away most of the complexity associated with contracts. When writing a smart contract using CashScript, these fields are easily available without the need to perform the steps of manually verifying and decoding the original Sighash image.

The first smart contract using guaranteed contract technology was Licho's Last Will (Last Will) , which is a smart contract that allows users to transfer the property of the deceased to their own. The contract defines three different functions. The first allows the successor to claim funds after 180 days. The second allows the owner's ColdKey to spend money in any way. The third allows the owner's Hot Key to refresh the 180-day period by forcing the entire contract balance to be sent back to the contract.

The CashScript version of Last Will is included below, but the original version was written by Spedn and can be viewed here.

This is one of the simple examples of useful guarantee contracts, but guarantee contracts enable even more complex functions. After the Last Will contract was signed, its founder Karol Trzeszczkowski went on to create Mecenas, which can enforce regular payments such as Patreon.

The guarantee contract was originally proposed in a paper entitled "Bitcoin Covenants", which required a new opcode _OP_CHECKOUTPUTVERIFY_. Other suggestions followed, such as _OP_CHECKTEMPLATEVERIFY_ or _OP_CHECKSIGFROMSTACK_. The latter is very similar to Bitcoin Cash's covenant implementation. Learn more about guaranteed contracts in Tendo Pein's article.

Simulated state

Look at the "Last Will" contract, and changing the successor when the contract is in place can be valuable. Since we can force a send to the current contract by looking at the bytecode of the current contract, we can force a send to a slightly different contract by slightly changing this bytecode. You can create a function that sends the balance of the entire contract to a contract that has exactly the same bytecode but different inheritors.

We can only do this using constructor parameters of known size (for example, 20 bytes). The constructor parameter is always the first data of the contract bytecode, and this is how we can easily replace the old data with the new data. The inheritor is the parameter of the first constructor, and its size is 20 bytes, so we can apply the technique, as you can see below.

By using this technique, certain variables in a contract can be changed while retaining the same rules of the contract. We call it "simulated state" because it provides some benefits of contract state and does not have the scalability problem of stateful systems like Ethereum. There are other disadvantages to this method, as there must be a trade-off somewhere.

The main problem is that we didn't actually change any of the variables in the original contract because this is not possible due to the stateless nature of Bitcoin Cash. Instead, create a new contract (with a new address) and transfer the entire balance to the new contract. This causes UX issues due to the new address, but these issues can be mitigated by having a good application layer abstraction on these smart contracts.

Replacing these variables inside the bytecode can be cumbersome, especially when trying to replace variables that are deeper inside the bytecode. This function should be abstracted in a high-level language to automatically generate new bytecode by providing new parameters. This abstraction might look like this:

Many abstractions come at the cost of larger contracts, which results in higher fees. However, Bitcoin Cash's transaction fees are usually very low, so it can be said to be a combination of the two. But Bitcoin Cash has the same size limitations as Bitcoin, so these abstractions do make it harder to stay within the limits. This has led many developers to have to manually optimize the compiled bytecode.

in conclusion

Each cryptocurrency is weighed in its smart contract system. Ethereum is the most widely used and most commonly used smart contract platform. Bitcoin provides a more basic version of smart contracts through its stateless scripting system. This stateless system is more efficient to verify but has fewer features. Bitcoin Cash has the same foundation as Bitcoin, but adds new features that try to compromise between valid verification and useful smart contracts. In the end, everyone is moving towards similar goals.

Looking to the future

This article was written in the fourth quarter of 2019 and reflects the current state of the platform. Cryptocurrencies are a fast-paced field, so people involved in these platforms are always struggling to improve, which may change the outlook of the ecosystem.

Ethereum is developing a major version of Ethereum 2.0, and Phase 0 is scheduled to go live in the first quarter of 2020. Ethereum 2.0 aims to address the performance issues of Ethereum 1.x by moving to proof of stake, implementing sharding and other improvements. The full roadmap for ETH2.0 has not yet been determined, and it may take years to launch. However, if this major update achieves its goals, it can provide strong support for Ethereum.

Smart contract research in Bitcoin is dedicated to further improving the efficiency and privacy of smart contracts, including solutions such as Taproot and scriptless scripting. Bitcoin Cash continues to work to enable other smart contract features and to make these changes more accessible.