Loomは、EVM (Ethereum Virtual Machine) 及びプラグインベースのスマートコントラクトをサポートする。 プラグインベースのスマートコントラクトは例えば go-loomで作成できる

このサンプルでは、Unity SDKを使用してプラグインベースのスマートコントラクトと対話する方法をデモンストレーションする。

サンプル コード

Assets/Samples/QuickStartに、このページの全コード及びLoom Unity SDK内で用意済みのUnityシーンがある。

DAppチェーンへの接続

Contract クラスは、Loom DAppチェーンで実行されるスマートコントラクトと対話するための便利な方法を提供する。 Loom SDKのサンプルスマートコントラクトBluePrint と対話するContract インスタンスを作成する関数を書いてみよう。

// LoomQuickStartSample.cs
using System;
using System.Threading.Tasks;
using UnityEngine;
using Loom.Unity3d;
using Loom.Unity3d.Samples;

public class LoomQuickStartSample : MonoBehavior
{
    async Task<Contract> GetContract(byte[] privateKey, byte[] publicKey)
    {
        var writer = RPCClientFactory.Configure()
            .WithLogger(Debug.unityLogger)
            .WithHTTP("http://127.0.0.1:46658/rpc")
            .Create();

        var reader = RPCClientFactory.Configure()
            .WithLogger(Debug.unityLogger)
            .WithHTTP("http://127.0.0.1:46658/query")
            .Create();

        var client = new DAppChainClient(writer, reader)
        {
            Logger = Debug.unityLogger
        };
        // required middleware
        client.TxMiddleware = new TxMiddleware(new ITxMiddlewareHandler[]{
            new NonceTxMiddleware{
                PublicKey = publicKey,
                Client = client
            },
            new SignedTxMiddleware(privateKey)
        });
        var contractAddr = await client.ResolveContractAddressAsync("BluePrint");
        var callerAddr = Address.FromPublicKey(publicKey);
        return new Contract(client, contractAddr, callerAddr);
    }
}

DAppチェーンへのデータの書き込み

スマートコントラクトの状態を変更するには、そのパブリックなメソッドのうちどれかを呼び出すことが必要であり、さらに署名済みのトランザクションが送信され、DAppチェーンによって検証されていなくてはならない。 幸いこれらのほとんどは、Contract.CallAsync() メソッドを使用すれば Contractクラスが処理を行う。

BluePrintスマートコントラクトは、パブリックなSetMsgメソッドを持っており、これはキーとバリューの連想配列を保存するよう呼び出すことができる。このメソッドは何も返さないことに気をつけること。 LoomQuickStartSampleクラスにBluePrint.SetMsg()を呼び出すメソッドを追加しよう。

async Task CallContract(Contract contract)
{
    await contract.CallAsync("SetMsg", new MapEntry
    {
        Key = "123",
        Value = "hello!"
    });
}

状態を変更するスマートコントラクトのメソッドは、値を返すことがある。 BluePrintスマートコントラクトは、パブリックなSetMsgEchoメソッドを持っており、これはキー/バリューの保存と、保存されたキー/バリューの返却を行う。 LoomQuickStartSampleクラスにBluePrint.SetMsgEchoを呼び出すメソッドを追加しよう。

async Task CallContractWithResult(Contract contract)
{
    var result = await contract.CallAsync<MapEntry>("SetMsgEcho", new MapEntry
    {
        Key = "321",
        Value = "456"
    });

    if (result != null)
    {
        // Unityコンソールウインドウにこのようにプリントされる: { "key": "321", "value": "456" }
        Debug.Log("Smart contract returned: " + result.ToString());
    }
    else
    {
        throw new Exception("Smart contract didn't return anything!");
    }
}

DAppチェーンからのデータの読み取り

スマートコントラクトの状態を読み取るには、そのパブリックな読み取り専用メソッドのうちどれかを呼び出すことが必要だ。読み取り専用メソッドの呼び出しで、スマートコントラクトの状態が変更されることはない。 スマートコントラクト上の読み取り専用メソッドは、Contract.StaticCallAsync() メソッドを使用して呼び出すことができる。

BluePrintスマートコントラクトは、パブリックなGetMsgメソッドを持っており、キーとバリューの連想配列を参照するようこれを呼び出すことができる。 LoomQuickStartSampleクラスにBluePrint.GetMsg()を呼び出すメソッドを追加しよう。

async Task StaticCallContract(Contract contract)
{
    var result = await contract.StaticCallAsync<MapEntry>("GetMsg", new MapEntry
    {
        Key = "123"
    });

    if (result != null)
    {
        // Unityコンソールウインドウにこのようにプリントされる: { "key": "123", "value": "hello!" }
        // 与えられた `LoomQuickStartSample.CallContract()` が初めに呼び出される。
        Debug.Log("Smart contract returned: " + result.ToString());
    }
    else
    {
        throw new Exception("Smart contract didn't return anything!");
    }
}

まとめ

LoomQuickStartSample クラスに次のメソッドを追加しよう。

// これで初期化する
async void Start()
{
    // 秘密鍵(privateKey)はDAppチェーンへ送られたトランザクションへ署名するために使われる。
    // 通常プレイヤー1人につき1つの秘密鍵を生成するか、もしくはプレイヤーが自身の秘密鍵を提供する。
    // このサンプルでは、毎回新しく鍵を生成している。
    var privateKey = CryptoUtils.GeneratePrivateKey();
    var publicKey = CryptoUtils.PublicKeyFromPrivateKey(privateKey);

    var contract = await GetContract(privateKey, publicKey);
    await CallContract(contract);
    // Unityコンソールウインドウにこのようにプリントされる: { "key": "123", "value": "hello!" } 
    await StaticCallContract(contract);
    // Unityコンソールウインドウにこのようにプリントされる: { "key": "321", "value": "456" }
    await CallContractWithResult(contract);
}

全コードの用意ができたので、テストしてみよう:

  1. Unityシーンに空のGameObjectを作成し、そこにLoomQuickStartSampleスクリプトを付け加えよう。
  2. スマートコントラクトBluePrintをローカルのLoom DAppチェーンノードにデプロイしよう。
  3. UnityエディターでPlayしてみよう。