Programming the Nxt Blockchain for fun and profit

Blockchains can be useful in various applications, facing global audience and supporting company internal infrastructure. A blockchain is a distributed database, a copy of the blockchain is stored on each node in a peer-to-peer network. This extreme redundancy can be duely considered inefficient, but please stay with me for a couple of minutes of blockchain theory.

As each node validates all transactions recorded into the blockchain and as past transactions cannot be rolled back or tampered with like in traditional RDBMS, this redundancy makes the blockchain *immutable*, and that is a very important value proposition of blockchains. Immutability of data is something traditional databases cannot provide. You may or may not need immutability of data and trust-free confirmation that data hasn’t been altered.

In this tutorial I assume you do need this.

One of the most versatile and flexible blockchains is the Nxt Blockchain (https://nxt.org). It has over a hundred API calls https://nxtwiki.org/wiki/The_Nxt_API.

Today you will learn basics of programming the Nxt blockchain. I will use only two API calls in this tutorial. With over a hundred API calls opportunities for programmers are limitless.

Application logic

A customer of a company or an employee in an organization uploads a file through a web form.
The file is renamed to a unique name and is saved in some location on the server.

A year later the customer / employee needs to verify, using the Nxt Blockchain, that the file hadn’t been altered. For instance, this may be required for legal purposes. It doesn’t have to be files. Internal company memos can be hashed and stored in the database, to be verified in a future audit.

Nxt allows us to send and record arbitrary messages (AM) into its blockchain.

Every transaction on the blockchain comes at a fee. If the transaction size is large, it can be expensive; fortunately Nxt has a subtype of AM called prunable messages. These are pruned after 90 days which make them cheap, they are available for retrieval from archival nodes after 90 days.

The maximum size of an arbitrary message in the Nxt blockchain is approx. 42 KB, the size of one block. A prunable message of 1 KB costs 1 NXT ($0.03). 1 KB is enough to store a hash of a file and this is our final cost to permanently record one hash in the immutable distributed Nxt blockchain.

As the customer uploads a file I create a SHA256 hash of the file and store the hash in the database in the organization’s server. For simplicity I’ve chosen SQlite, but you can use Mysql, Postgresql, Oracle. I will use PDO to access SQlite database in PHP.

When we do not use the immutable database (blockchain), the file can be modified, the new hash of the modified file saved in the database, making it hard to prove the file was like this from the beginning.

Blockchain comes to the rescue

Every prunable message can be retrieved from archival nodes. Every record in the blockchain is immutable. You can be sure the hash of the file you uploaded a year ago, when it is retrieved from the blockchain, is the same hash. All you need now is compare it with the hash in the organization’s internal RDBMS.

Pre-requisites:
PHP with curl, json and some db extension (I use sqlite3). A web server is optional, you can use php-cli. Java 8 (Oracle or OpenJDK to run Nxt). Nxt reference software: https://nxtforum.org/nrs-releases/nrs-v1-10-1/.

Install the NRS (Nxt Reference Software (depending on the context interchangeably called Nxt Client or Nxt Server)) and create an account. Fund it with a few coins. You can exchange Bitcoin to NXT at an exchange service like https://shapeshift.io or exchange with someone at https://nxtforum.org. It is also possible to “mine” some free NXT as reward for running a node; http://test.nxter.org/the-forging-bounty-lottery-campaign-will-pay-5-million-in-rewards-to-forgers-and-nxt-nodes/.

First we create a simple database table for our application, nothing fancy, you can add more column types if you must store more information. I like to use DB Browser for SQLite of http://sqlitebrowser.org.

Let’s make an empty database ‘files.db’ and save it in /home/lurker10/phptutorial/files.db

Using DB Browser for SQLite create the following table.

CREATE TABLE "files" (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`txid` TEXT,
`hash` TEXT,
`uploadtime` TEXT,
`filename` TEXT
)

‘txid’ is the field for storing the id of a transaction we receive from Nxt when the transaction is accepted. It is unique. ‘hash’ is the sha256 hash of the file.

In this tutorial I skip the file upload part of code to keep it concise.

Let’s assume the file is already uploaded and stored on the web server. We define the file location variable in the code.

$uploadDir = "/home/lurker10/phptutorial/tmp/";
$fileName = "copy12345.tar";

By default the Nxt Server listens for API requests on port 7876. If you run it on the same machine as your php code, your code must send queries to http://127.0.0.1:7876/nxt

The other important variables are the passphrase of the Nxt account you’ve created and funded and the recipient’s account.

You can send the message to yourself, recipient can be your own account.

$host = "http://127.0.0.1:7876/nxt";
$secretPhrase = "your passphrase";
$recipientID = "NXT-XXXX-XXXX-XXXX-XXXXX";

The next part of code is the function that submits query using curl in a POST request.

To make a query we must define $payload and $payload_string variables and feed them to sendRequest(). It is possible to run the Nxt Server over HTTPS and use curl to verify the SSL certificate, but for this simple app we have disabled SSL verification in the curl connection.

Another point of interest is the $errorDescription, json-decoded from server response.

If there is a problem with the query (“Not enough funds” in your account when your balance is zero),
you must add error handling routine. I omit this too. For this app I assume the server responded properly, and return the response into the app for further processing.

function sendRequest($host, $payload, $payload_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $host);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 10000);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 10000);
curl_setopt($ch, CURLOPT_POST, count($payload));
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload_string);
$output = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);
$errorDescription = trim(@json_decode($output)->errorDescription);
if ($errorDescription != "") { // perform error handling; return false; }
return $output;
}

As the file is uploaded already, I create a sha256 hash of the file and timestamp.

$fileHash = hash_file("sha256", $uploadDir.$fileName);
$txTime = time();

I will use PDO to work with the database.

Open the db and insert a new record.

We don’t know the txid until we talk to the Nxt Server that can give it to us when transaction is accepted on the NXT network, so for now I’ll insert null for txid.

$pdo = new PDO('sqlite:/home/lurker10/phptutorial/files.db');
$sql = "INSERT INTO files (txid, hash, uploadtime, filename)
VALUES (null, '$fileHash', '$txTime', '$fileName')";
$result = $pdo->exec($sql);

Next we create a query to send to the NXT server.

This particular query is “sendMessage”, you can find a whole lot more queries to interact with the blockchain and their mandatory and optional parameters at https://nxtwiki.org/wiki/The_Nxt_API.

As I said earlier the fee to transact is 1 NXT. 1 NXT = 100,000,000 NQT (nanoquants).
1 NQT is the smallest unit of denomination in NXT same as 1 satoshi in Bitcoin.
The Nxt Server accepts the fee in NQT, so we pay exactly 100 million NQT ($0.03)

The “broadcast” parameter can be changed to false, in this case you will receive ‘transactionBytes’ in the response, which can be broadcast to the network later using the ‘broadcastTransaction’ request. But today I have set it to ‘true’ to broadcast the transaction instantly.

Remember to urlencode() the message. I insert the filename separated from the hash with a colon into the message.

$payload = array(
"requestType" => "sendMessage",
"recipient" => $recipientID,
"secretPhrase" => urlencode($secretPhrase),
"feeNQT" => 100000000,
"deadline" => 1440,
"broadcast" => "true",
"message" => urlencode($fileName . ":" . $fileHash),
"messageIsPrunable" => "true"
);
$payload_string = "";
foreach ($payload as $key => $value) {
$payload_string .= $key . "=" . $value . "&";
}
rtrim($payload_string, "&");

Send the query to NXT server using sendRequest() function:

$output = sendRequest($host, $payload, $payload_string);

and decode the JSON response from the server to get the transaction id:

if ($output != false) {
$txId = json_decode($output)->transaction;
}

Now that there is a positive response on the accepted transaction and its ID is known, let’s update the record in the in-house db.

$lastId = $pdo->lastInsertId();
$sql = "UPDATE files SET txid = '$txId' where id = '$lastId'";
$result = $pdo->exec($sql);

We can optionally provide these links to the customer for future reference and to prove that the hash was uploaded:

echo "NXT Transaction ID: " . $txId . ",
JSON response";
echo "

Use these links to verify Sha256 hash of your file saved in our internal database against the permanent record in the NXT blockchain:

" . $fileHash;

Optionally email the customer the $txId that they can later use to verify hash or somehow else give them basic information on retrieval of the hash from in-house db and comparing it to blockchain stored hash in the future, by timestamp or other criteria.

This app doesn’t include user authentication. Normally the customer or user of an intranet service would be able to see their files after having authenticated to the site.

This app also assumes that the verification app is out of reach of the in-house database maintainer to prevent faking verification outcome.

Now the record is saved in the company’s database. Show the db record to confirm it’s there.

$sth = $pdo->prepare("SELECT id, txid, hash, uploadtime, filename FROM files ORDER BY id DESC");
$sth->execute();
$result = $sth->fetch(PDO::FETCH_OBJ);
if ($result != false) {
var_dump($result);
}

The verification app

To use the hash verification app the customer must have the transaction ID in the NXT blockchain
passed to them when the transaction was submitted to the Nxt Blockchain.

Suppose the customer does have it, saved in the mail archive or retrieved by other means.
Here it is.

$txId = "111111111111111111";

Let us see what our in-house database has for the hash of the file. Fetch and save it in $hashInDb.

$pdo = new PDO('sqlite:/home/lurker10/phptutorial/files.db');
$sth = $pdo->prepare("SELECT hash FROM files where txid = '$txId'");
$sth->execute();
$result = $sth->fetch(PDO::FETCH_OBJ);
if ($result != false) {
$hashInDb = $result->hash;
}

Send a request to the NXT server and fetch all information stored in the NXT blockchain for transaction with the given ID.

$payload = array (
"requestType" => "getTransaction",
"transaction" => $txId
);
$payload_string = "";
foreach ($payload as $key => $value) {
$payload_string .= $key . "=" . $value . "&";
}
rtrim($payload_string, "&");

$output = sendRequest($host, $payload, $payload_string);

Decode the JSON response and extract the attachment field where the hash is stored.

In the first part of the app we recorded the filename separated from the hash with a colon.
Now we extract just the hash portion of the arbitrary message.

$attachmentPlainData = json_decode($output)->attachment->message;
$hashInBlockchain = explode(":", $attachmentPlainData)[1];

And compare what we have in the company’s database with what was recorded 1 year ago into the Nxt Blockchain.

if ($hashInDb == $hashInBlockchain)
echo "Hashes are identical";
else
echo "Hashes are not identical";

Next part of this series: Lottery on the Nxt Blockchain in Golang (and PHP)

NXT-crypto-developer

View this in: Español

Leave a Comment