C# client
We are currently updating this documentation. While it offers a general overview, some details may be outdated. Please check back soon for the latest version.
The C# client provides functionality for interacting with a blockchain using C#. It allows you to send transactions and retrieve information from a blockchain node running Rell. It can be integrated into your C# projects through the NuGet package or directly referencing the DLL files. Additionally, specific instructions apply if you're working with Unity or Unity WebGL.
You can access the project repository here
Usage
Native
The Postchain client can be installed from nuget or referenced through DLLs from the releases.
Unity
The NET Standard 2.1 DLL is compatible and can be imported into Unity. Unpack the contents from the releases section and add them to the Unity project.
Unity WebGL
WebGL is not compatible with System.Net
used in the DefaultTransport. You may need to implement your Transport or use
Unity/UnityTransport.cs
. The following code must be executed to inject it into the client code before a
ChromiaClient
is created.
ChromiaClient.SetTransport(new UnityTransport());
Initializing the client
It can be initialized from RID or IID (chain ID). It also accepts a collection of node urls, where requests are evenly distributed. Should a request to one node fail, the other nodes will be tried to access.
var blockchainRID = Buffer.From("7d565d92fd15bd1cdac2dc276cbcbc5581349d05a9e94ba919e1155ef4daf8f9");
var client1 = await ChromiaClient.Create("http://localhost:7740", blockchainRID);
var client2 = await ChromiaClient.Create("http://localhost:7740", 0);
var client3 = await ChromiaClient.Create(new() {"http://localhost:7740", "http://localhost:7741"}, 0);
Connecting to a network is achieved through the Directory System Chain. CreateFromDirectory
accepts an array of URLs
to system nodes running the directory chain. This directory chain is automatically queried to determine the URLs of the
nodes in the network running the target dapp.
var blockchainRID = Buffer.From("7d565d92fd15bd1cdac2dc276cbcbc5581349d05a9e94ba919e1155ef4daf8f9");
var client1 = await ChromiaClient.CreateFromDirectory("http://localhost:7750", blockchainRID);
var client2 = await ChromiaClient.CreateFromDirectory("http://localhost:7750", 42);
var client3 = await ChromiaClient.Create(new() {"http://localhost:7750", "http://localhost:7751"}, 0);
Queries
Queries return dapp data from the blockchain. They are invoked with typed parameters or an object implementing
IGtvSerializable
. Properties in the query object can be mapped to Rell query parameters through the JsonProperty
attribute. It automatically parses the data to the given type.
struct QueryParams : IGtvSerializable
{
[JsonProperty("zip")]
public int Zip;
}
var response = client.Query<string>("get_city", ("zip", 22222));
response = client.Query<string>("get_city", new QueryParams(){ Zip = 22222 });
Transactions
To send transactions, begin by creating a simple signature provider. The signature provider is used to sign transactions.
var signer1 = SignatureProvider.Create(); // creates a new random keypair
var signer2 = SignatureProvider.Create(Buffer.Repeat('a', 32)); // from private key
Transactions send operations to the node that executes Rell code. Operations can be created dynamically or through the
constructor. The parameters can also be passed as an IGtvSerializable
object. The order of the parameter list has to
match the operation in the Rell code. This also applies to the order of the properties in the IGtvSerializable
object.
struct OperationParams : IGtvSerializable
{
public string City;
public int Zip;
}
var op1 = new Operation("insert_city", "hamburg", 22222);
var op2 = new Operation("insert_city")
.AddParameter("hamburg")
.AddParameter(22222);
var op3 = new Operation("insert_city", new OperationParams(){
City = "hamburg",
Zip = 22222
});
Transactions can be created dynamically per static method or through the client. The Sign
method signs the transaction
by all added signature providers. A transaction can also be sent unsigned. If at least one signature provider is added
to the transactions, SendTransaction
signs the transaction before sending it.
var op = new Operation("insert_city", "hamburg", 22222);
var tx1 = Transaction.Build()
.AddOperation(op)
.AddSignatureProvider(signer1);
client.SendTransaction(tx1);
var tx2 = client.TransactionBuilder()
.AddOperation(op)
.AddSignatureProvider(signer1);
var signedTx = tx2.Sign();
client.SendTransaction(signedTx);
Some transactions may need to be signed by multiple signers at different locations. The following transaction needs to
be signed by two signers. One signer can create a Signature
and share it with the other signer. They can import and
add the signature to the Sign
method as a pre-signed signature.
var tx = Transaction.Build()
.AddOperation(new Operation("insert_city", "hamburg", 22222))
.AddSigner(signer1.PubKey)
.AddSigner(signer2.PubKey);
var signature = tx.Sign(signer1);
// signer1 sends the signature.Hash and their pubkey to signer2
var signature = new Signature(signer1.PubKey, Buffer.From("<hash>"))
tx.AddSignatureProvider(signer2);
var signedTx = tx.Sign(signature);
client.SendTransaction(signedTx);
To create transactions with the same operations but different transaction RID, a "no-operation" (nop) operation can be added. Alternatively, the transaction can be sent as a unique transaction, which automatically adds a nop.
var tx = Transaction.Build()
.AddOperation(new Operation("insert_city", "hamburg", 22222))
.AddNop()
.AddSignatureProvider(signer1.PubKey);
client.SendUniqueTransaction(tx);
Error handling
In general, the client throws exceptions when it runs into error. The code is documented to show all possible exceptions
thrown by each method. Logic errors by the client throw ChromiaException
or its subclass TransportException
. The
TransportException
contains information about which part of the Transport failed and contains HTTP status codes (if
applicable).