Technical description of the platform

Smart contracts

Smart contract is a separate application which saves its entry data in the blockchain, as well as the output results of its algorithm. The Waves Enterprise blockchain platform supports development and usage of Turing complete smart contracts for creation of high-level business applications.

When a smart contract is launched on a blockchain network, nobody can arbitrarily change its code, spoof it or restrict its operation without interference with the entire network. This aspect allows to provide security of business applications.

Smart contracts can be developed in any programming language and do not have any restrictions for their internal logic.

The Waves Enterprise blockchain platform implements two types of smart contracts:

Smart contracts use node’s API to access the node state for data exchange. Docker smart contracts use the gRPC API interface for this purpose. WASM smart contracts access the node’s API directly.

Each smart contract has its own balance, which can hold tokens. For more details on managing tokens from a Docker smart contract see below. Managing tokens from a WASM smart contract is done in the same way.

Each network participant can create and call smart contracts.

A smart contract is created and updated by the same account. This may pose a threat to smart contract security: for example, a leaked mnemonic phrase from the account may allow an attacker to update the contract and withdraw funds. To prevent such situations, you can use the Smart Account technology as an additional security feature.

If you need to restrict access to a smart contract, create a confidential smart contract. Only the nodes you list when creating the smart contract will be able to call it and receive its result. You will be able to modify this list of nodes in the future. Learn more about confidential smart contracts:

Important

In release 1.14.0, WASM smart contracts do not support atomic transactions and confidential smart contracts.

The node implements MVCC (Multiversion concurrency control) mechanism – control of concurrent access to smart contracts state through multiversion. With this feature the node can execute multiple transactions of any smart contracts in parallel. Data consistency is guaranteed. The MVCC mechanism is implemented in the same way for Docker and WASM smart contracts.

Docker Smart Contracts

A Docker smart contract is executed in a Docker container. This keeps the launch and execution of the smart contract separate from the blockchain platform itself.

A developed smart contract is packed in a Docker image which is stored in the open Waves Enterprise registry. This repository is based on the Docker Registry technology, every smart contract developer has an access to it.

In order to upload your smart contract into the registry, contact the Waves Enterprise technical support service. After your request is approved, your smart contract will be uploaded into the registry, and you will be able to call the smart contract in the platform Client or using a REST API query to your node.

If you are going to use Docker smart contracts in your own private blockchain network, you have to create your own registry for smart contract uploading and calling.

Docker smart contract operation chart

The general chart of Docker smart contract operation is provided below:

../../_images/docker-1.png

Handling tokens from a Docker smart contract

As of release 1.12, after the 1120 feature activation, Waves Enterprise blockchain platform smart contracts have their own balance, which can store WEST system tokens as well as other tokens. For the smart contracts created on the previous versions, the balance of the WEST system tokens is set to zero.

Also, smart contracts can now perform basic operations with tokens:

  • issue tokens,

  • reissue tokens,

  • burn the tokens on the smart contract balance,

  • transfer tokens from the smart contract balance to a user’s (users’) balance by the user’s (users’) address.

These functions are implemented by the CommitExecutionSuccess gRPC API method.

With this functionality, smart contracts can change the states of assets and users (their balances). Users can also send tokens to a smart contract balance.

Development and installation of Docker smart contracts

Practical instructions on development of smart contracts, as well as an example of a smart contract in Python are listed in the article Development and usage of smart contracts.

A participant developing smart contracts should have the contract_developer permission in the network. This permission allows a participant to upload and call smart contracts, as well as to restrict operation of his own smart contracts and change their code.

Development of a smart contract starts with preparation of a Docker image which contains a ready smart contract code, its Dockerfile and, in case of usage of a smart contract with the gRPC interface for data exchange with the node, all required protobuf files.

The prepared image is built with the use of the build utility of the Docker package, and after this is upload into the registry.

In order to install and work with smart contracts, you have to set up the docker-engine section of the node configuration file. If your node works in the Waves Enterprise Mainnet, it already has the pre-set parameters for smart contracts installation from the open repository, as well as the recommended parameters for optimal operation of smart contracts.

Installation of smart contracts in the blockchain is performed with the use of the 103 CreateContract Transaction. This transaction should contain a link to the image of the smart contract in the registry. It is recommended to send the latest versions of transactions while working with smart contracts.

In private networks, the 103 transaction allows to install Docker images of smart contracts not only from repositories stated in the docker-engine section of the node configuration file. If you need to install a smart contract from a registry not included in the list of the configuration file, type the full address of a smart contract in the registry you have created in the name field of the 103 transaction. An example of 103 transaction fields is provided in its description.

Upon receiving the 103 transaction, the node downloads the smart contract image specified in the image field. After that, the downloaded image is verified by the node and started in the Docker container.

Calling a Docker smart contract and saving the results of its operation

A smart contract is called for operation by a network participant using the 104 CallContract Transaction.

This transaction transfers the smart contract Docker container id, as well as its input and output parameters in the form of key-value pairs.

The container is started if it has not been started before.

The smart contract is executed and sends the result via the gRPC API interface to the node that initiated the start of the smart contract. The node, in turn, generates a 105 ExecutedContract Transaction with the result of the smart-contract execution. This way the result of the smart contract execution is recorded in its state by means of the 105 ExecutedContract transaction.

Validator nodes verify that everyone who executed that smart contract with that data got the same result. If the verification is successful, the miner node places the transactions into the block, and the result of the smart contract execution goes into the blockchain.

Restriction of Docker smart contract calls

To disable smart contract calls on the blockchain, submit the 106 DisableContract Transaction specifying the contractId – contract identifier on the blockchain network. This transaction can only be sent by the creator of this smart contract with the non-expired contract_developer permission.

When disabled, a smart contract becomes unavailable for further calls. The data of disabled smart contracts is stored in the blockchain and can be obtained with the use of gRPC and REST API methods.

Updating Docker smart contracts

If you have changed the code of your smart contract, update it. To do this, upload your smart contract into the Waves Enterprise registry by sending a request for updating of your smart contract to the Waves Enterprise technical support service.

Then send the 107 UpdateContract Transaction to your node. The contract to be updated should not be disabled with a 106 transaction.

After updating of the smart contract, mining nodes of the blockchain download it and check correctness of its operation. After that, information about update of the smart contract is included into its state with the use of the 105 transaction containing data of the corresponding 107 transaction.

Hint

Only the participant with the contract_developer role who created the 103 CreateContract Transaction for this smart contract can modify the contract.

Docker smart contracts validation

The WE blockchain platform supports three smart contract validation policies to provide its additional integrity control. This opportunity is available under following conditions:

  • The 162 soft fork is activated in the network;

  • The network includes one or more participants with the contract_validator permission;

  • The version 4 (and higher) 103 and 107 transactions are used to create and update smart contracts.

The validation policy is configured with the use of the validationPolicy.type field of corresponding transaction.

Available validation policies:

  • any - the general validation policy is kept in the network: to mine the updated smart contract, the miner signs the corresponding 105 transaction. Also, this parameter is set if there are no registered validators in the network.

  • majority - a transaction is considered valid if it is confirmed by the majority of validators: 2/3 of the total number of registered addresses with the contract_validator permission.

  • majorityWithOneOf(List[Address]) - the transaction is considered valid if the majority of validators is collected, among which there is at least one of the addresses included in the parameter list. The addresses included in the list must have a valid contract_validator permission.

Warning

If the validation policy majorityWithOneOf(List[Address]) is selected, the address list must contain at least one address; passing an empty list is not allowed.

Docker smart contracts parallel operation

The Waves Enterprise platform allows to run multiple smart contracts simultaneously. For this purpose, the node implements the MVCC (Multiversion concurrency control) mechanism – parallel access control through multiversion. The mechanism allows multiple transactions of containerized smart contracts to run in parallel and maintain data consistency.

All transactions are divided into two groups:

  1. non-executable transactions – atomic containers and all the classic transactions: transfer transaction, data transaction, etc.;

  2. executable transactions – transactions of all containerized smart contracts.

Transactions of the first group are always executed sequentially (the level of parallelism is 1). For the second group of transactions, the execution parallelism is determined by the value of the node.docker-engine.contracts-parallelism parameter in the node configuration:

node.docker-engine.contracts-parallelism = 8

The default value is 8. In this way, all smart contracts are executed in parallel, independently of the Docker image.

Note

There is competition between the two groups of transactions: if heterogeneous transactions accumulate in the UTX pool, concurrency may decrease. This behavior can be smoothed by increasing the pulling buffer size, but it cannot be completely eliminated.

The code logic of a smart contract, as well as its programming language, should take into account the peculiarities of parallel operation of smart contracts. For instance, if a smart contract containing a function of increment of a variable upon every smart contract call transaction operates simultaneously, its result will be incorrect, because a common authorization key is used for each smart contract call.

API methods available for Docker smart contracts

The platform provides the gRPC API methods to exchange data between a smart contract and a node. Use these methods to perform a wide range of operations with the blockchain.

Learn more:

WASM Smart contracts

Unlike Docker smart contracts, WASM smart contracts are a compiled byte code that is executed on a WEVM virtual machine. This approach improves the stability and speed of contract execution by eliminating additional components and communication between them, because the virtual machine is integrated inside the platform.

Important

WASM smart contracts can be used on the Waves Enterprise platform starting with release 1.14.0 after 1140 feature activation.

Key benefits of WASM:

  • High performance and compatibility,

  • Small size of WASM byte code,

  • Isolated and platform-independent design,

  • Extended language support.

Important

In release 1.14.0, WASM smart contracts do not support atomic transactions and confidential smart contracts.

WASM Smart contract operation chart

A WASM smart contract is a base-64 WASM byte-code located inside ContractInfo.

The main difference between WASM smart contract implementation and Docker smart contract implementation is accessing the node API directly without using the gRPC API.

The general chart of WASM smart contract operation is provided below:

../../_images/wasm_en.png

When a WASM smart contract is executed, a WASMService is created that accesses blockchain functionality (provides an interface to a DelegatedBlockchain instance such as TransactionsAccumulator).

WASMContractExecutor calls executeTransaction. Inside the executeTransaction, WASMExecutor calls the execution of the smart contract bytecode (runContract) and its validation (validateBytecode).

  • In case of a CreateContractTransaction, the runBytecode method is called with the _constructor function passed in.

  • In case of an UpdateContractTransaction, the runBytecode method is not called; ContractExecutionSuccess is returned with empty changes.

  • In case of a CallContractTransaction, the runBytecode method is called with the callFunc function passed in CallContractTransaction. The function in CallContractTransaction cannot be _constructor.

When the next block is formed, the transaction is retrieved from the UTX pool, a one-time instance of the WASMService class is created, and the transaction is accumulated via WASMService.

WASM smart contract development

WASM smart contract can be developed in any programming language that supports source code compilation into WebAssembly bytecode. The virtual machine provides the necessary set of functions for writing contracts of any complexity. Before creating a WASM contract on the platform, all you need to do is compile it.

Practical instructions on WASM smart contracts development are listed in the WASM smart contracts development and usage article.

Creating and calling a WASM smart contract

The same transactions as for Docker contracts are used to create and call WASM smart contracts.

To create a contract, you must specify the byte code of the contract as a base64 string and its byte code hash in 103 CreateContract transaction version 7.

Important

A participant developing smart contracts must have the contract_developer permission on the network. With this permission the participant can call smart contracts, as well as change his own smart contracts code and restrict their operation.

All WASM contracts are stored inside the blockchain state, so no additional downloads or third-party services are required when the contract is launched.

A WASM smart contract is called for operation by a network participant using the 104 CallContract Transaction version 7. To call a WASM contract, you must specify the function to be called and the list of arguments required for the function.

Capturing the results of WASM smart contract execution

The result of the contract execution is 0 if the contract executed successfully, or an error code:

Error codes

Error code

Error name

Condition that returns the error

100

InvalidBytecode

Failed to recognize and validate the WASM bytecode

101

ConstructorNotFound

Failed to find the contract constructor

102

MemoryError

Error when working with virtual or linear memory

103

MemoryLimits

Memory size limit below u32::MAX

104

LinkerError

Error when working with Linker instances

105

InstantiateFailed

Failed to create and run WASM bytecode

106

HeapBaseNotFound

Unable to find Global heap base

107

FuncNotFound

Failed to find a function

108

InvalidNumArgs

Invalid number of arguments

109

FailedParseFuncArgs

Failed to recognize function argument

110

FailedDeserializeDataEntry

Failed to recognize DataEntry arguments

111

FailedExec

Failure during execution

112

StackOverflow

Call stack overflow error

304

no data for this key: <key>

Attempt to access a key for which storage is not initialized

501

DataIsMissing

There is no contractKey or contractBytecode

502

InvalidArgument

An invalid argument was passed from WEVM, e.g. invalid recipient address

503

InvalidTransfer

Transfer errors, e.g. when trying to pass a value less than 0 to Transfer or creating too many transfers to the contract balance (payments field)

If a contract makes any changes to its state, or performs an operation on assets, the WASMService captures such changes by calling external functions (Environment).

The smart contract is executed and sends the result via API to the node that initiated the smart contract launch. The node, in turn, generates a 105 ExecutedContract Transaction with the result of the smart-contract execution. This way the result of the smart contract execution is fixed in its state using the 105 ExecutedContract transaction.

Validator nodes verify that everyone who executed that smart contract with that data got the same result. If the verification is successful, the miner node places the transactions into the block, and the result of the smart contract execution goes into the blockchain.

Prohibiting WASM smart contract calls

WASM smart contract can be disabled in the same way as Docker smart contract.

Updating WASM smart contracts

If you have changed your WASM smart contract code, update it using the 107 UpdateContract Transaction version 7.

Important

You cannot update a smart contract that has been disabled by means of the 106 DisableContract Transaction.

Hint

Only the participant with the contract_developer role who created the 103 CreateContract Transaction for this smart contract can modify the contract.

WASM smart contracts validation

To provide additional integrity control for WASM smart contracts, the blockchain platform supports the same validation policies as for Docker smart contracts.

Parallel execution of WASM smart contracts

Multiple smart contracts can be run simultaneously on the Waves Enterprise platform. For this purpose, the node implements the MVCC (Multiversion concurrency control) mechanism – managing parallel access to the state of smart contracts through multiversionality. The mechanism allows multiple transactions of containerized smart contracts to run in parallel and maintain data consistency.

The MVCC mechanism for WASM smart contracts is similar to the mechanism for Docker smart contracts.

See also