# Smart Contract
# Basic Information of Smart Contract
Miyabi allows users to use smart contracts for handling complex operations towards tables. When using a smart contract, the user needs to specify the name of the smart contract, functions, and parameters. All the direct operations to tables can be defined in the smart contract.
Miyabi supports smart-contract written in C# 8.0. A smart contract is a C# class inherited from ContractBase
in Miyabi and import-related modules for operations. ContractBase
provides some methods to access the world state and a predefined binary table that is owned by the smart contract for storing metadata. Smart contracts support fundamental operations in and whitelisted libraries in C#. The World State can be accessed and modified through a smart contract if necessary credentials are included in the required credential of the transaction that invokes the smart contract.
A smart contract in Miyabi has a complete life cycle. First, the source code and dependencies will be compiled and analyzed by a Roslyn Analyzer where several checks are applied. Once the code passes analysis, it can be deployed to the Miyabi. The user needs to instantiate the smart contract first and specify an instance owner to it. Then, the user can invoke methods of the instance by transactions. When a node executes these transactions, the node will create an instance of the smart contract and bind it to the internal table for execution. If an exception is thrown, the transaction will be marked as failed and discard changes. Users can also query the smart contract through API to read data according to the logic. To abolish one instance, the instance owner can delete the instance record, so that no one can invoke/query this instance.
# Create a Smart Contract
A normal smart contract is written in C# like following:
public class SampleContract:ContractBase
{
public override bool Instantiate(string[] args)
{
// instantiate code
}
public void InvokeMethod(string[] args)
{
// Method invokes through transactions
}
public string QueryMethod(string[] args)
{
// Method queried through API
}
}
A contract must inherit from ContractBase
, and the invoked method should not return any value because transactions only return the result code. To update the world state in the invoked method, the user can use the StateWriter
member defined in ContractBase
.
Miyabi provides two templates derived from the ContractBase
for developers. TransformableSmartContract
defines a SaveState
function. Developers can override it with logic that the user wants to execute after every invocation. UpgradableContractBase
provides some tool functions to hand over table ownership. Developers can use the preserved GrantTables
method to implement the logic that needs to be done when upgrading one instance to a different instance and call it from the new instances.
More details are in the SDK documents and sample code.
# Deploy Smart Contract
A Miyabi smart contract's method can be used only after it is deployed, which means the source code is stored to all nodes of Miyabi. To deploy a smart contract, the transaction should be signed by an address with Deploy
permission, who should apply the first layer security check for the smart contracts. Once a smart contract is deployed, the compiled source code will become a part of World State, and registered to a predefined table for managing smart contracts. Miyabi uses a unique assembly Id, the hash value of source code, to distinguish different smart contracts. Since the same source code will have the same assembly Id, developers cannot deploy the same smart contract twice.
To deploy a smart contract, user need to provide the following parameters.
Item | Type | Description |
---|---|---|
Referenced Assemblies | List of string | libraries used by the smart contract that needed to be imported |
Source Code | List of string | the source codes |
Instantiators | List of Public Key | The owner of the smart contract who can instantiate this smart contract. |
# Instantiate Smart Contract
Since a smart contract is a class, we need to create an instance for the smart contract before using it. The user needs to instantiate the smart contract, which will create an instance record and an internal table to store metadata of this instance. Instantiating a smart contract needs the assembly Id, class name, and an instance name for that instance. In Miyabi, the hash of the above three parameters is theInstanceId
for strictly distinguish different instances.
Method Instantiate
is defined in ContractBase
as an empty method. Developers can override the Instantiate
function to store variables and create tables for other methods. A predefined internal table can store the metadata of the smart contract used and created during the instantiating.
To Instantiate an instance, the user needs to provide the following parameters. The transaction needs to be signed by one instantiator
of the assembly, and other addresses according to the required permissions.
Item | Type | Description |
---|---|---|
Assembly Id | string | The assembly Id of the deployed smart contract. It can be checked by cli command getassemblyid |
Instance Name | string | The Instance Name provided by user to distinguish different instance |
Contract Name | string | The Class inherited Contract Base and whose instantiate function will be called |
Instance Owners | List of Addresses | The addresses who can delete this instance |
Arguments | list of string | An array provide all the parameters needed for instantiate functions |
# Invoke Smart Contract
In Miyabi, the user can invoke different methods of the smart contract to change the World State. Users can only invoke the method with a void return type and check the result by transaction result code. To invoke a method, the user needs to create an entry to point out which method of which instance will be called and provide the required parameters.
The input parameters can only be:1. ByteString
(Defined in Miyabi); 2. PublicKey
; 3. Address
(Defined in Miyabi); 4. Json string
. The following objects cannot be treated as input parameters: 1. Object
; 2. Empty
; 3. DateTime
; 4. DBNull
. The user needs to serialize all the parameters into a JSON format string, and the executor will deserialize them according to the definition of methods in the smart contract.
To Invoke a method of smart contract, the user needs to provide the following parameters.
Item | Type | Description |
---|---|---|
Assembly Id | string | The assembly Id of the deployed smart contract. It can be checked by cli command getassemblyid |
Instance Name | string | The Instance Name provided by user to distinguish different instance |
Contract Name | string | The class inherited Contract Base and whose instantiate function will be called |
Method Name | string | The Method invoked in the smart contract. Must return void. |
Arguments | list of string | An array provide all the parameters needed for instantiate functions |
# Query Smart Contract
Users can use the API to query the smart contract. Since the query will not be a part of the consensus, query methods cannot change the world state. In return, the query methods have a non-void return type as the HTTP response.
To query a method, the following parameters are needed:
Item | Type | Description |
---|---|---|
Assembly Id | string | the assembly Id of the deployed smart contract. It can be checked by cli command getassemblyid |
Instance Name | string | The Instance Name provided by user to distinguish different instance |
Contract Name | string | The class inherited Contract Base and whose instantiate function will be called |
Method Name | string | The Method invoked in the smart contract. Must return void. |
Arguments | List of string | An array provide all the parameters needed for instantiate functions |
The endpoint is {miyabiAPI}/query/{assemblyId}/{contractName}/{instanceName}/{methodName}?{Aruguments[0]}="xxx"...
. The result will be returned through the HTTP message.
# Contract Event
Users can also store their customized data into the event through the smart contract. Users need to define their event data derived from ContractEventBase
and use ExecutionContext.TriggerEvent(event)
to trigger the event builder. Each event can define some bytes string in the filter FilterData
, used in the bloom filter of the block event for quick searching in a block.