Building Applications on Liquid¶
Liquid Application Overview¶
Applications can make use of Liquid’s Remote Procedure Call (RPC) interface to develop applications on Linux, Windows and Mac OS in any language capable of handling RPC request-response messaging over HTTP.
Examples are provided in Python, C#, Ruby, Go, Perl, and Java. The Python and C# examples are expanded to cover web applications using Flask and the .NET Core MVC frameworks.
In the Developer Guide section, the terminal is used to send commands to the Liquid client (elements-cli), which in turn issues RPC commands to the Liquid daemon (elementsd) or the Liquid Core GUI (elements-qt). This configuration will be familiar to those who develop for Bitcoin.
The communication between daemon and client is possible because, when started in server or daemon mode, elementsd initiates an HTTP server and listens for requests being made to it on a port specified in the elements.conf file.
Requests to the daemon are made by posting JSON formatted data to the HTTP server port that elementsd or elements-qt are listening on. The request is processed and the results are returned as JSON formatted data.
Verification details of the credentials needed to make these calls are stored in the elements.config file so the client making the RPC requests can satisfy the authentication checks of the daemon.
Take a look in the elements.conf file and notice the rpc related settings. If there are none then you will have to add some. The “chain” setting tells Liquid to run on the live Liquid network (liquidv1) or another network, such as regtest (elementsregtest). The following settings tell Liquid to start in regtest mode and that it can be accessed over RPC using the username “user1” and the password “password1”. You should change the values used to a secure username and password.
# Start as a background process and accept RPC
daemon=1
# Set RPC details for client authentication
rpcuser=user1
rpcpassword=password1
# Regest settings
chain=elementsregtest
elementsregtest.rpcport=18884
elementsregtest.port=18886
# To connect to other local liduidd instances:
elementsregtest.connect=localhost:18887
# Live network settings:
# chain=liquidv1
# rpcport=18884
# To validate peg-ins
validatepegin=1
# RPC details (as set in bitcoin.conf)
mainchainrpcport=18888
mainchainrpcuser=userOfBitcoinRPCHere
mainchainrpcpassword=passwordOfBitcoinRPCHere
# Other config settings you want to use can go here:
In our examples, we will be connecting to elementsd in regtest mode, using the regtest authentication details and port number above to send requests to the Liquid daemon. You should change the example code to match what you have set in your own elements.conf.
Please note that the examples listed below are intended to get you to the point where you have a functioning setup which you can use as a building block for further development.
Python¶
In this example we will be using Python to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic Python code. We will be using the popular AuthServiceProxy Python JSON-RPC interface to handle the connection, authentication and data typing for us as we communicate with our node. We’ll also use virtualenv to create an isolated environment to run our code in.
You can check if Python is installed on your system by following the steps here. We’ll assume you already have Python3 installed.
First we will need to install a few prerequisites. From the terminal run the following commands one after another:
sudo apt-get install python3-pip
sudo pip3 install virtualenv
Create a directory named “liquidpython” and move into it:
cd
mkdir liquidpython
cd liquidpython
Set up and activate virtualenv in that directory:
virtualenv venv
source venv/bin/activate
Use pip to install python-bitcoinrpc within the environment:
pip3 install python-bitcoinrpc
That will have set up all we need for our Python example code.
Create a new file named liquidpython.py in the “liquidpython” directory and paste the code below into it.
from __future__ import print_function
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
rpc_port = 18884
rpc_user = 'user1'
rpc_password = 'password1'
try:
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:%s"%(rpc_user, rpc_password, rpc_port))
result = rpc_connection.getwalletinfo()
print(result["balance"]["bitcoin"])
except JSONRPCException as json_exception:
print("A JSON RPC Exception occured: " + str(json_exception))
except Exception as general_exception:
print("An Exception occured: " + str(general_exception))
The code defines the details needed to connect to Liquid using RPC commands, sets up the method we want to execute and the parameter we want to pass in, executes the call and prints out the “balance” value from the results.
Before we try running the code make sure the Liquid daemon (elementsd) or Liquid QT (elements-qt) are running.
To run our Python code execute the following command:
python3 liquidpython.py
The result of which should be the balance is written to the terminal.
When you have finished, deactivate virtualenv:
deactivate
When you want to run your code again, activate the environment from within the “liquidpython” directory, run the code and then deactivate when finished:
source venv/bin/activate
python3 liquidrpcpython.py
deactivate
Obviously that’s a very basic example but you now have a functioning setup which you can use as a building block for further development. The next section takes the code above and implements it within a Python web application using Flask.
Python Web (Flask)¶
In this example we will be using Python (running within the Flask web framework) to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic Python code. We will be using the popular AuthServiceProxy Python JSON-RPC interface to handle the connection, authentication and data typing for us as we communicate with our node. We’ll also use virtualenv to create an isolated environment to run our code in.
You can check if Python is installed on your system by following the steps here. We’ll assume you already have Python3 installed.
We will use the Python code from the previous Python example and have it run from Flask so that we can write the output to a web page.
Assuming you have already installed the prerequisites from the previous example (i.e. python3-pip, virtualenv), we just need to set up the environment and install Flask:
cd
mkdir liquidpythonflask
cd liquidpythonflask
virtualenv venv
source venv/bin/activate
pip3 install python-bitcoinrpc
pip3 install Flask
Before we try running any code make sure the Liquid daemon is running.
Create a file named liquidpythonflask.py, into which you should paste the following code. We are using AuthServiceProxy to handle the connection, authentication and data typing for us as we communicate with our Liquid node.
Tip
Python requires that lines are indented correctly. Make sure the code below is copied correctly and is using 4 spaces for indenting lines. Also note that some of the lines below wrap when viewed in a browser.
from flask import Flask
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
app = Flask(__name__)
@app.route("/")
def liquid():
rpc_port = 18884
rpc_user = 'user1'
rpc_password = 'password1'
try:
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:%s"%(rpc_user, rpc_password, rpc_port))
result = rpc_connection.getwalletinfo()
except JSONRPCException as json_exception:
return "A JSON RPC Exception occured: " + str(json_exception)
except Exception as general_exception:
return "An Exception occured: " + str(general_exception)
return str(result['balance']['bitcoin'])
if __name__ == "__main__":
app.run()
Start the web server and execute our code:
FLASK_APP=liquidtutorial.py flask run
You should see the web server startup. Now all you have to do is open a browser and go to:
Which simply writes the result of the “balance” call to the page.
The example is intended to get you up and running. You now have a functioning setup which you can use as a building block for further development using Flask.
C# .NET Core¶
The .NET Core framework runs on Linux, Windows and Mac OS. We will use C#, the most popular .NET language, to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic C# code.
Installing the .NET Core SDK
You can skip this step if you already have the .NET Core SDK installed. The installation instructions are based upon Linux and will vary depending on which OS you are using.
Before installing the .NET Core SDK, you’ll need to register the Microsoft key used to validate the required repository, register the product repository itself, and then install the required dependencies.
Open a command prompt and run the following two commands.
Note that the command you run after “wget” is dependant on the which distribution of Linux you are running. Please check the .NET SDK download page to get the right one. There are only two lines below so note the text wrap. The first starts with “wget”, the second with “sudo”.
wget -q packages-microsoft-prod.deb https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
Now we can install the .NET Core SDK:
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install dotnet-sdk-2.1.4
Creating the application
Create a simple template console app:
dotnet new console -o liquiddotnet
cd liquiddotnet
dotnet run
That will create a file in $HOME/liquiddotnet called Program.cs, execute the code within and output the following:
Hello World!
Edit the Program.cs file in $HOME/liquiddotnet using a text editor, change the contents to the following and then save the file: (note that some of the lines below wrap when viewed in a browser)
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace liquiddotnet
{
class Program
{
private static HttpClient client = new HttpClient();
static void Main(string[] args)
{
MainAsync().GetAwaiter().GetResult();
}
private static async Task MainAsync()
{
string url = "http://user1:password1@localhost:18884";
var contentData = new StringContent(@"{""method"": ""getwalletinfo"", ""jsonrpc"": ""2.0""}", System.Text.Encoding.UTF8, "application/json");
using (HttpResponseMessage response = await client.PostAsync(url, contentData))
using (HttpContent content = response.Content)
{
string data = await content.ReadAsStringAsync();
if (null != data)
{
Console.WriteLine(data);
}
}
}
}
}
Running the application
Before you try running any code, make sure the required daemon is running.
Move to the the directory with the file in, compile and run the application:
cd
cd liquiddotnet
dotnet run
Which outputs the results of the getwalletinfo command.
As an application would be making multiple calls to the Liquid daemon via RPC you will probably want to move the code that actually does the request and response work into its own function. An example of how to do this is the dynamic JSON RPC class, a C# wrapper class intended to enable simple dynamic JSON RPC calls to Bitcoin, Liquid, Elements and other RPC enabled daemons.
The code above is a starting point to get you up and running and you now have a functioning setup which you can use as a building block for further Liquid development.
C# .NET Core (MVC)¶
The .NET Core framework runs on Linux, Windows and Mac OS. We will use C#, the most popular .NET language, within an MVC web application to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic C# code.
Installing the .NET Core SDK
Before starting, check that you have installed the required prerequisites from the previous example.
Creating the application
We will be using the Model, View, Controller (MVC) pattern for our app. We will also be using an existing class to handle the calls to Liquid daemon and simplify our code. We will amend the default Home controller to call this class and pass the data it returns back to the relevant View using a new Model that we’ll also create.
To get started, create a directory for our MVC app and move into it:
mkdir LiquidMVC
cd LiquidMVC
Use the dotnet tool to create a new template mvc site. This will set up the required folder structure, files, and configuration needed to serve the web app:
dotnet new mvc
Check it is set up correctly by running the app:
dotnet run
When it says the application has started, browse to https://localhost:5001
You should see the template site running, all we have to do is add our own code to what’s already there.
Shut the app down using Ctrl+C.
Now we will start adding our own code so that we can query our Liquid node and display the results on the app’s home page.
Create a new file named “dotnetcoreDynamicJSON-RPC.cs” in the LiquidMVC directory and paste in the raw code of the “Dynamic JSON RPC class” and save it. Alternatively, clone the GitHub repository into a different directory and copy the dotnetcoreDynamicJSON-RPC.cs file into your LiquidMVC directory.
This class is a C# wrapper class intended to enable simple dynamic JSON RPC calls to Bitcoin, Liquid, Elements, and other RPC enabled daemons. The project, along with examples of how to use it, can be found in the repository. All we need for now though is to copy the code from the raw link
That class enables us to easily query our node. We’ll add the code to call it soon, first we need a way to pass the data that we get back from our node to the web page for display. For that we need a Model. We’ll create a simple one that you can add to later.
Create a new file named “ExampleNodeInfo.cs” in LiquidMVC/Models and paste the following into it:
using System;
namespace LiquidMVC.Models
{
public class ExampleNodeInfo
{
public string Balance { get; set; }
public string Message { get; set; }
//Add whatever other properties you want here
}
}
Now we have a way to get data from our node and a Model that lets us pass the data to the View for display.
Open the HomeController.cs file in LiquidMVC/Controllers. We will be adding code to call the Dynamic JSON RPC class to get data from our Liquid node, populate our Model with the results and hand the Model to the landing page’s View for display.
To the top of the HomeController.cs file, add the following:
using DotnetcoreDynamicJSONRPC;
Then replace the Index method so it looks like the following. Note that some of the lines below wrap when viewed in a browser.
public IActionResult Index()
{
// We will be using a Liquid node in this example.
// It is easy to switch to use a Bitcoin, Liquid or Elements node.
// You need to change these to make sure you can authenticate against the daemon you are running:
string rpcUrl = "http://localhost";
string rpcPort = "18884";
string rpcUsername = "user1";
string rpcPassword = "password1";
// For examples and notes on how to use the dotnetcoreDynamicJSON-RPC tool and its JSON helper methods please see:
// https://github.com/wintercooled/dotnetcoreDynamicJSON-RPC
// Initialise an instance of the dynamic dotnetcoreDynamicJSON_RPC class.
dynamic dynamicRPC = new DynamicRPC(rpcUrl, rpcPort, rpcUsername, rpcPassword);
// Initialise our model that will be passed to the view
var nodeInfo = new ExampleNodeInfo();
if (dynamicRPC.DaemonIsRunning())
{
try
{
// Get the JSON result of the 'getwalletinfo' RPC on the Liquid node.
string balance = dynamicRPC.getwalletinfo();
// Use the DotnetcoreDynamicJSONRPC 'GetProperty' string helper to return the property value we want.
balance = balance.GetProperty("result.balance.bitcoin");
// Populate the model
nodeInfo.Balance = balance;
}
catch (Exception e)
{
nodeInfo.Message = e.Message;
}
}
else
{
nodeInfo.Message = "Could not communicate with daemon";
}
// Return the view and the associated model we have populated
return View(nodeInfo);
}
Next, edit the Index.cshtml file in LiquidMVC/Views/Home and replace all the existing content with the following code. The code takes our Model and displays the data in it on the default web page.
@model LiquidMVC.Models.ExampleNodeInfo
@{
ViewData["Title"] = "Index";
}
<h2>Example Node Info</h2>
@{
if (Model.Message != "")
{
<h3>@Model.Message</h3>
}
}
<div>
<h4>Basic Wallet Info</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Balance)
</dt>
<dd>
@Html.DisplayFor(model => model.Balance)
</dd>
</dl>
</div>
Running the application
Before you try running the code, make sure the Liquid daemon is running. Make sure your terminal is at the LiquidMVC directory level and run the following:
dotnet run
When it says the application has started, browse to https://localhost:5001
The balance of the Liquid node’s wallet is displayed on the page.
That should have got you up and running and in order to extend your application, you can look at the examples on the Dynamic JSON RPC class GitHub site.
Go¶
In this example we will be using Go to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic Go code.
To install Go: https://golang.org. Note the importance of setting the PATH environment variable.
Create a directory src/liquid inside your Go workspace directory (probably %HOME/go) so that the full path is: $HOME/go/src/liquid
With that directory create a file named “liquidrpcgo.go” and past the following into it:
package main
import (
"log"
"bytes"
"net/http"
"io/ioutil"
"encoding/json"
)
func main() {
url := "http://user1:password1@localhost:18884"
var jsonStr = []byte(`{"jsonrpc":"1.0","method":"getblockcount","params":[]}`)
request, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
request.Header.Set("Content-Type", "application/json")
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)
log.Println(string(body))
//Use as JSON...
var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
panic(err)
}
blocks := dat["result"].(float64)
log.Println(blocks)
}
Compile and run the code:
go build
./liquid
The code prints out the current block count.
You now have a functioning setup which you can use as a building block for further development.
Ruby¶
In this example we will be using Ruby to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic Ruby code.
You can check if Ruby is installed on your operating system, and install it if not, by following the steps on the Ruby language website.
Create a new file named “liquidrpcruby.rb” and paste the code below into it:
require 'net/http'
require 'uri'
require 'json'
class LiquidRPC
def initialize(service_url)
@uri = URI.parse(service_url)
end
def method_missing(name, *args)
post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
resp['result']
end
def http_post_request(post_body)
http = Net::HTTP.new(@uri.host, @uri.port)
request = Net::HTTP::Post.new(@uri.request_uri)
request.basic_auth @uri.user, @uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
end
class JSONRPCError < RuntimeError; end
end
if $0 == __FILE__
liquid = LiquidRPC.new('http://user1:[email protected]:18884')
p liquid.getblockcount
end
Execute the code from the command line:
ruby liquidrpcruby.rb
The output will show the current block count.
You now have a functioning setup which you can use as a building block for further development.
Java¶
In this example we will be using Java to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic Java code.
The example code doesn’t require any external dependencies, but you do need the Java compiler (javac) as well as the Java runtime environment itself. These can be installed on Ubuntu using the command:
sudo apt install default-jdk
Create a new file named “liquidrpcjava.java” and paste the code below into it:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
public class liquidrpcjava {
public static void main (String []args) throws IOException{
URL url = new URL ("http://127.0.0.1:18884");
String rpcuser ="user1";
String rpcpassword ="password1";
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication (rpcuser, rpcpassword.toCharArray());
}
});
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json; utf-8");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
String json = "{\"method\": \"getwalletinfo\", \"jsonrpc\": \"2.0\"}";
try(OutputStream os = conn.getOutputStream()){
byte[] input = json.getBytes("utf-8");
os.write(input, 0, input.length);
}
try(BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))){
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line.trim());
}
System.out.println(sb.toString());
}
}
}
Compile and run the code from the command line:
javac liquidrpcjava.java
java liquidrpcjava
The output will show wallet information.
You now have a functioning setup which you can use as a building block for further development.
Perl¶
In this example we will be using Perl to make a Remote Procedure Call (RPC) to the Liquid daemon, which you will need to start using the config file settings outlined above.
Our aim is simply to make a call to Liquid using RPC by executing some basic Perl code.
Perl can be installed from https://www.perl.org and comes pre-installed on Ubuntu.
We will be using the JSON::RPC::Client Perl implementation of a JSON-RPC client which will make the rpc calls and results handling simpler.
To install JSON::RPC::Client open the CPAN tool from the terminal:
perl -MCPAN -e shell
And from within the cpan console, install the RPC Client:
install JSON::RPC::Client
And then exit the cpan tool:
quit
You must close the terminal window so that when we run the code below it will pick up the new environment variables written.
Create a new file named “liquidrpcperl.pl” and paste the code below into it:
use JSON::RPC::Client;
use Data::Dumper;
my $client = new JSON::RPC::Client;
$client->ua->credentials(
'localhost:18884', 'jsonrpc', 'user1' => 'password1'
);
my $uri = 'http://localhost:18884/';
my $obj = {
method => 'getwalletinfo',
params => [],
};
my $res = $client->call( $uri, $obj );
if ($res){
if ($res->is_error) { print "Error : ", $res->error_message; }
else { print Dumper($res->result); }
} else {
print $client->status_line;
}
Run the code from the command line (remember that this must be a new terminal window from the one we used before to install the RPC Client):
perl liquidrpcperl.pl
The output will show wallet information.
You now have a functioning setup which you can use as a building block for further development.