Skip to the content.

Basic Node

In this section, we will create a simple Unity application that does the following:

Creating a Unity Project

First and foremost, install Unity Hub first2. Once finished, open Unity Hub and from InstallsInstall Editor, install Unity Editor version 2021.3.0f13. After Unity Editor installation is done, go to Projects and select New Project. From the New Project screen, select 2D Core, select a location to save your project, and name it Clicker. Once everything is set up, click on Create Project and wait for Unity Editor window to show up.

Importing UniLibplanet Unity Package

Download the latest UniLibplanet.unitypackage from the UniLibplanet repository. From Unity Editor, select AssetsImport PackageCustom Package from the top menu and select the downloaded [UniLibplanet.unitypackage] file. Confirm with Import to import everything.

Basic UI

As the application will be running on top of a blockchain, our first objective is to render the state of the blockchain itself on a screen. We will be creating a basic UI to draw the Hash and the Index of the tip of the blockchain in real time. For this, we create the following UI components:

Running in Background

As a blockchain node, we need to make sure that the application isn’t paused while in background. Otherwise, UI update together with mining and/or block syncing process will hang when the application window is not in focus, and generally this is not how we would want a blockchain node to behave. Under the Unity Editor’s menu, navigate to EditProject SettingsPlayer and make sure Run In Background option is enabled.

Creating a Scene

Perform the following step by step in Unity Editor:

When finished, the Hierarchy panel should look something like below.

Hierarchy Panel

Initial UI Script

Create a file named Game.cs under Assets/Scripts with the following content:

using UnityEngine;
using UnityEngine.UI;

namespace Scripts
{
    public class Game : MonoBehaviour
    {
        public Text BlockHashText;
        public Text BlockIndexText;

        public void Awake()
        {
            BlockHashText.text = "Block Hash: 0000";
            BlockIndexText.text = "Block Index: 0";
        }
    }
}

Connecting UI to the Script

Finally, we connect the script above to the UI using the following steps:

When done, the Inspector panel for GameObject should look like below.

Game Object

Try Build and Run from Unity Editor. If everything was done accordingly, you should see Block Hash: 0000 and Block Index: 0 on your screen.

Initial UI

Rendering Blocks

Now, let’s try to run a blockchain node. Update the content of Game.cs we already have created previously with the following:

using System.Collections.Generic;
using Libplanet.Action;
using Libplanet.Blocks;
using Libplanet.Blockchain.Renderers;
using Libplanet.Unity;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;

namespace Scripts
{
    // Unity event handler.
    public class BlockUpdatedEvent : UnityEvent<Block<PolymorphicAction<ActionBase>>>
    {
    }

    public class Game : MonoBehaviour
    {
        // Connected to UI elements.
        public Text BlockHashText;
        public Text BlockIndexText;

        private BlockUpdatedEvent _blockUpdatedEvent;
        private IEnumerable<IRenderer<PolymorphicAction<ActionBase>>> _renderers;
        private Agent _agent;

        // Unity MonoBehaviour Awake().
        public void Awake()
        {
            // General application settings.
            Screen.SetResolution(800, 600, FullScreenMode.Windowed);
            Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.ScriptOnly);

            // Register a listener.
            _blockUpdatedEvent = new BlockUpdatedEvent();
            _blockUpdatedEvent.AddListener(UpdateBlockTexts);

            // Renderers are called when certain conditions are met.
            // There are different types of renderers called under different conditions.
            // Some are called when a new block is added, some are called when an action is executed.
            _renderers = new List<IRenderer<PolymorphicAction<ActionBase>>>()
            {
                new AnonymousRenderer<PolymorphicAction<ActionBase>>()
                {
                    BlockRenderer = (oldTip, newTip) =>
                    {
                        // FIXME: For a genesis block, this renderer can get called
                        // while Libplanet's internal BlockChain object is not
                        // fully initialized.  This is a haphazard way to bypass
                        // NullReferenceException getting thrown.
                        if (newTip.Index > 0)
                        {
                            _agent.RunOnMainThread(() => _blockUpdatedEvent.Invoke(newTip));
                        }
                    }
                }
            };

            // Initialize a Libplanet Unity Agent.
            _agent = Agent.AddComponentTo(gameObject, _renderers);
        }

        // Unity MonoBehaviour Start().
        public void Start()
        {
            // Initialize texts.
            BlockHashText.text = "Block Hash: 0000";
            BlockIndexText.text = "Block Index: 0";
        }

        // Updates block texts.
        private void UpdateBlockTexts(Block<PolymorphicAction<ActionBase>> tip)
        {
            BlockHashText.text = $"Block Hash: {tip.Hash.ToString().Substring(0, 4)}";
            BlockIndexText.text = $"Block Index: {tip.Index}";
        }
    }
}

In order for an application to react to a blockchain level event, such as a change in the tip of the local blockchain and/or created actions getting executed, the application needs to pass a set of callback methods for an Agent to call. These are called renderers and must implement the IRenderer interface.

In the example above, when the tip of the blockchain changes, the blockchain calls the method

BlockRenderer = (oldTip, newTip) =>
{
    if (newTip.Index > 0)
    {
        _agent.RunOnMainThread(() => _blockUpdatedEvent.Invoke(newTip));
    }
}

where it is picked up by UpdateBlockTexts() method as it was added as a listener to _blockUpdatedEvent in the previous part of the code.

For now, just note Agent is simply a wrapper class for handling a Libplanet blockchain node. Also don’t worry about PolymorphicAction<ActionBase> for now. This will be explained further later.

Running a Blockchain Node

In order to run a Libplanet blockchain node, the following three are needed:

These three files can be easily created using Unity Editor menu. Create each using Create genesis block, Create swarm config, and Create private key under ToolsLibplanet.

Now, you can build and run the application. If you see the Block Hash text and the Block Index text on your screen updating periodically, then you are now running a blockchain node!

Running

At first, block index might be going up rather fast, but after a while, the blockchain will adjust accordingly and slow down.


Footnotes

  1. The tip of a blockchain is a Block with the highest Index

  2. This tutorial is written with Unity Hub 3.1.2. 

  3. At this moment, only Unity Editor version 2021.3.0f1 is supported.