# Smart Contract
# Introduction
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.
ContractBase
provides WorldState
read and write abstraction.
A smart contract owned Binary table is also created when a smart contract instance is created, the developers can use this for storing various data (general metadata and bookkeeping etc.).
The smart contracts can use allowed assemblies and members to accomplish various logical operations.
The getcontractanalyzerparameters
and updatecontractanalyzer
commands list and update the parameters for the smart contract analyzer respectively.
The WorldState
can be accessed and modified through a smart contract if necessary credentials are included in the transaction that invokes
the smart contract instance.
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 Miyabi.
The user needs to instantiate the smart contract first and specify an instance owner for it.
Then, the user can invoke the contract instance methods by using transactions, or query its read-only methods.
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 the changes will be discarded.
Also, the instance owner can delete the instance record so no one can invoke/query this instance.
This document shall provide examples with the following sample smart contract: sc1.cs
# Create a Smart Contract
A simple smart contract, written in C#, looks like the 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
}
}
All the smart contracts in Miyabi inherit from the ContractBase
class, either directly or indirectly.
The invoked method should not return any value because transactions only return the result code.
To update the WorldState
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.
# Get Assembly Id
The Assembly Id
is the hash of the Miyabi smart contract source code.
getassemblyid
is an offline command that calculates the assembly id of the smart contract without compiling the source code.
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.
# Example
$ ./miyabi-cli.exe getassemblyid -f sc1.cs
c71ceb0566944e7874510e88c51302694857db853c01d2d099c0eaf53ea9962b
# Deploy Smart Contract
The first step to use a smart contract is to deploy it to Miyabi. The deployment step ensures that the smart contract is using valid code (no disallowed assemblies and members) and also that the source code is compilable. The assembly of the smart contract is then stored by Miyabi nodes.
To deploy a smart contract, the transaction should be signed by an address with contract Deploy
permission.
Once a smart contract is deployed, the compiled source code will become a part of WorldState
, and registered to a predefined table for managing smart contracts.
A deploy smart contract transaction has the following parameters:
Item | Type | Description |
---|---|---|
Contract Admin Private Keys | PrivateKey[] | Private key(s) of the signer with 'Deploy' contract permission (optional) |
Source Files | string[] | File path to the smart contract source |
Instantiators | Address[] | Address(es) which can administer the creation of the contract instances |
Dependencies | string[] | Assembly name of third party dependencies (optional) |
Debug | bool | Deploy as debuggable smart contract (optional) |
# Example
$ ./miyabi-cli.exe sendtransaction deploycontract -p 14e3a2d16c8a43a4eb1b088b32bca2abaf274e3f185afc9c15b33491c8deb9a6 -i 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 -f sc1.cs
0083b12ba492fa2c38cd8c21cce90eeb56c2e4b442f9baeb4f45f6016dd1620f
# Instantiate Smart Contract
The deployed smart contract exists as a compiled assembly in Miyabi.
To use the deployed smart contract, the user needs to create an instance of the smart contract.
The contract instantiation 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 aforementioned three parameters constitutes the InstanceId
for strictly distinguishing different instances.
Method Instantiate
is defined in ContractBase
as a virtual overridable method that returns true
by default.
Developers can override the Instantiate
method to do any startup operations like creation of tables or storing some initial data.
The predefined internal table for each smart contract instance can also be used for storing the metadata or any data in general.
The ContractInstantiate
transaction needs to be signed by at least one Instantiator
address, and other addresses according to the required permissions.
To create a new instance of a deployed smart contract, the user needs to provide the following parameters:
Item | Type | Description |
---|---|---|
Assembly Id | ByteString | Assembly Id of the deployed smart contract |
Instance Name | string | Instance name for the new instance of the deployed smart contract |
Contract Name | string | The class inherited ContractBase and whose instantiate function will be called |
Instance Owners | Address[] | Address(es) of instance owner. Deletion of an instance requires it's signature |
Instantiator Private Keys | PrivateKey[] | Private key of user or valid signer as defined in contract (optional) |
Arguments | string[] | An array containing all the parameters needed for the instantiate function (optional) |
# Example
$ ./miyabi-cli.exe sendtransaction instantiatecontract -p 01 -p 10425b7e6ebf5e0d5918717f77ce8a66aaf92bc64b65996f885ff12bd94ef529 -a c71ceb0566944e7874510e88c51302694857db853c01d2d099c0eaf53ea9962b -c Miyabi.Tests.SC1 -i test_sc1_instance -o 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 --argument dummy
7712535ac74a2567fd456726acd82d96fae49aa82c888260fe4a9ec5a7a44e07
# Invoke Smart Contract
Users can invoke methods of a smart contract instance to do various operations. A smart contract method can potentially:
- make changes to
WorldState
- make changes to the local data of the smart contract instance
- communicate with other smart contracts
- or do some idempotent operations, etc.
Users can only invoke
the method with a void
return type and check the result by transaction result code.
Contract invocation can be done using a ContractInvoke
transaction entry, in which, the user can input the method name and the respective arguments of the method to be invoked.
To Invoke a method of smart contract, the user needs to provide the following parameters.
Item | Type | Description |
---|---|---|
Assembly Id | ByteString | Assembly Id of the deployed smart contract |
Instance Name | string | Instance name provided by user to distinguish different instance |
Contract Name | string | The class inherited ContractBase and whose instantiate function will be called |
Method Name | string | The method invoked in the smart contract. Must return void |
Arguments | string[] | An array provide all the arguments needed for the method being invoked (optional) |
Instantiator Private keys | PrivateKey[] | Private key of user or valid signer as defined in contract (optional) |
The method arguments can be of following types:
ByteString
PublicKey
Address
- Primitive types
- Miyabi types serialized as JSON string
The following objects cannot be treated as input parameters: Object
, Empty
(Null reference), DateTime
, 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.
# Example
$ ./miyabi-cli.exe sendtransaction invokecontract -a c71ceb0566944e7874510e88c51302694857db853c01d2d099c0eaf53ea9962b -c Miyabi.Tests.SC1 -i test_sc1_instance -p 01 -m Write --argument 1111 --argument 2222
f76f01358d9f04f9982dced015d68f0762e3f87e60d9bf6c033e56f0aa596181
# Contract Event
Users can also store their customized data into the event through smart contracts.
Users need to define their event data derived from ContractEventBase
and use IContractExecutionContext.TriggerEvent(event)
to trigger the event builder.
The event data can be serialized to ByteString and stored in the filter FilterData
, used in the bloom filter of the block event for quick searching in a block.
# Query Smart Contract
Users can use the API to query the smart contract. The contract query request is a read request to the WorldState
and can't make any changes to it.
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 | ByteString | Assembly Id of the deployed smart contract |
Instance Name | string | Instance name provided by user to distinguish different instance |
Contract Name | string | The class inherited ContractBase and whose instantiate function will be called |
Method Name | string | Name of the smart contract method |
Parameters | string[] | An array containing all the parameters needed for the query method being invoked (optional) |
# Example
$ ./miyabi-cli.exe querycontract -a c71ceb0566944e7874510e88c51302694857db853c01d2d099c0eaf53ea9962b -c Miyabi.Tests.SC1 -i test_sc1_instance -m Read -p 1111
"2222"
# Delete Smart Contract Instance
In Miyabi smart contract user can delete the instance of a deployed contract with the help of instance owner's signatures.
To delete an instance of smart contract, the user needs to provide the following parameters.
Item | Type | Description |
---|---|---|
Assembly Id | ByteString | Assembly Id of the deployed smart contract |
Instance Name | string | Instance name of the smart contract to be deleted |
Contract Name | string | The class inherited ContractBase and whose instantiate function will be called |
Instantiator Private keys | Privatekey[] | Private key(s) of the smart contract instance owners (optional) |
# Example
$ ./miyabi-cli.exe sendtransaction deletecontractinstance -p 01 -p 10425b7e6ebf5e0d5918717f77ce8a66aaf92bc64b65996f885ff12bd94ef529 -a c71ceb0566944e7874510e88c51302694857db853c01d2d099c0eaf53ea9962b -c Miyabi.Tests.SC1 -i test_sc1_instance
b1895869ce09373d1d7435d24f307768183b3743c1ac5c2972f63dd9be033cca