Blockchains share a single state between each node participating in the network, called the distributed ledger. Nine Chronicles uses Libplanet
to manage the blockchain state, which in turn implements many of the gameโs features, and Lib9c
is the implementation.
๐ก
This document is based on Libplanet 5.2.2
, Lib9c 1.17.3
, and Bencodex 0.16.0
versions.
- For more information on how to use Libplanet, see the official documentation.
- Lib9c 1.17.3
- Bencodex 0.16.0
Address โ
In Libplanet, an address represents a specific location on the blockchain, and is primarily used to identify accounts and their state. Libplanet has a class Address
that acts as an address and is usually derived from a public key[1] or generated as a hexadecimal string of 40 or 42 digits.
PrivateKey privateKey = new PrivateKey();
PublicKey publicKey = privateKey.PublicKey;
Address addressFromPublickKey = publicKey.Address;
// or
Address addressFromPrivateKey = privateKey.Address;
Address addressViaHexString1 = new Address("1234567890abcdef1234567890abcdef12345678");
// or
Address addressViaHexString2 = new Address("0x1234567890abcdef1234567890abcdef12345678");
World(IWorld) โ
In Libplanet, blockchain state can be managed through the IWorld
interface, which provides methods to retrieve and update accounts (IAccount, CurrencyAccount). In this context, an account is a bundle of states associated with a particular address in the world.
public IWorld Foo(IWorld world)
{
Address address = new PrivateKey().Address;
IAccount account = world.GetAccount(address);
world = world.SetAccount(address, account);
Currency currency = Currency.Uncapped("$", 0, null);
CurrencyAccount currencyAccount = world.GetCurrencyAccount(currency);
world = world.SetCurrencyAccount(currency, currencyAccount);
return world;
}
Account(IAccount) โ
In Libplanet, you can manage status through the IAccount
interface.
public IAccount Foo(IAccount account)
{
Address address = new PrivateKey().Address;
IValue? value = account.GetState(address);
if (value is null)
{
account = account.SetSate(address, (Bencodex.Types.Integer)1);
}
else
{
account = account.RemoveState(address);
}
return account;
}
CurrencyAccount โ
CurrencyAccount represents an account associated with a specific currency, and is primarily used to manage balance status.
public CurrencyAccount Foo(
CurrencyAccount currencyAccount,
Address sender,
Address recipient)
{
Currency currency = Currency.Uncapped("$", 0, null);
FungibleAssetValue balance = currencyAccount.GetBalance(sender, currency);
// balance: 0.0 $
FungibleAssetValue amount = new FungibleAssetValue(currency, 1, 0);
currencyAccount = currencyAccount.MintAsset(sender, amount);
balance = currencyAccount.GetBalance(sender, currency);
// balance: 1.0 $
currencyAccount = currencyAccount.TransferAsset(sender, recipient, amount);
balance = currencyAccount.GetBalance(sender, currency);
// balance: 0.0 $
balance = currencyAccount.GetBalance(recipient, currency);
// balance: 1.0 $
currencyAccount = currencyAccount.BurnAsset(recipient, amount);
balance = currencyAccount.GetBalance(recipient, currency);
// balance: 0.0 $
balance = currencyAccount.GetBalance(sender, currency);
}
IValue โ
Libplanet stores all state serialized in the Bencodex.Types.IValue
interface type. There are many different implementations, including Bencodex.Types.Binary
, Bencodex.Types.Integer
, Bencodex.Types.Text
, Bencodex.Types.List
, and Bencodex.Types.Dictionary
.
public IAccount Add(IAccount account, Address address, int value)
{
IValue? state = account.GetState(address);
return state switch
{
null => account.SetState(address, (Bencodex.Types.Integer)value),
Bencodex.Types.Null => account.SetState(address, (Bencodex.Types.Integer)value),
Bencodex.Types.Integer i => account.SetState(address, i + value),
_ => throw new UnexpectedTypeException();
}
}
The public key derived from the private key. Libplanet.Crypto.PublicKey โฉ๏ธ