# Smart Contract
# Basic Information of Smart Contract
Miyabi defines series of transaction for handling tables. Besides, 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#. A smart contract needs to inherited from ContractBase in Miyabi and import related modules for operations. ContractBase provides some methods to access to the world state and a predefined binary table that can only be accessed within a smart contract for storing metadata. Fundamental operations and libraries in C# can be used in smart contracts and the World state can be accessed and modified if necessary signatures are provided in the transaction that invokes the smart contract.
Miyabi has several systems to protect the security of smart contracts. First, the source code and dependencies will be compiled by a Roslyn analyzer where several checks are applied. Once the code passes compiling, it can be deployed to the Miyabi. User needs to instantiate the smart contract first and then invoke different methods of the instance by entries. When a node is executing a transaction, Miyabi will invoke the instance of the smart contract according to the entry. If an exception is thrown or Kotowari finds any invalid change to tables, the transaction will be marked as failed and no change will be applied to the world state.
# 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. InstanceId is predefined for users to get the instance Id of the current Instance. If the contract is inherited from TransformableSmartContract, a SaveState function can be overridden which will be executed every time after the invoked method is finished. 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 the deploy admin which can apply the first layer security check for smart contracts. Once a smart contract is deployed, the 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 to distinguish different smart contract which is the hash value of source code. Since the same source code will have the same assembly Id, one piece of code cannot be deployed 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
To initial the smart contract, the user needs to instantiate it after deploying. Instantiate a smart contract will create an instance of the deployed source code and give an Instance name to the instance. In Miyabi, another Instance Id will be used to strictly distinguish different instances for all smart contracts.
Instantiate is defined in ContractBase as an empty method. If the smart contract wants to initialize anything, it can override the instantiate function and use a string array to manage input parameters. A predefined Internal table can be used to store the metadata of the smart contract during the instantiating.
To Instantiate a 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 |
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. User needs to serialize all the parameters into a json format string, and the node 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
If users only want to get some information from the smart contract without modifying it, they can use the API of nodes to make a query of the smart contract. All users can use API to query a method of an instantiated smart contract. However, since the query will not provide any valid signatures to the node and no entry will be created for making transactions, All changes in the queried method will be discarded. On the other hand, the result of the query can be returned through API, which means the query method allows a not void return type.
To use query 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.
# Event
Block event is a specific area in the Block Body used for store plain data. Event contains the block id and a set of transaction events. Each transaction events contains a filter and a set of triggered events. For simplification, we use event to denote triggered event. Event is used for data which are generated during execution of transactions and will not be stored into world state. Currently, Miyabi support two ways to trigger events: predefined entry and smart contract.
Currently, only consensuschangeentry will trigger a system event that store the new credentials and the height it will take effect. This event will be automatically stored in the block where this entry is committed.
Users can also store their customized data into event through 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 FilterData which will be used to create a bloom filter for quick searching in block.
User can get events from block through API GetBlockEvents and use Blockevent.Events.Any(a => a.Maycontain(filterdata))
to judge if the block contains the specific event. User can get generate filterdata by combing all predefined FilterData in an empty EventFilterData.