block-magic

Simple Web data I/O on Secure Blockchain


Keywords
Web, I/O, blockchain
Install
pip install block-magic==2.6.2

Documentation

blockmagic logo rigo logo

BlockMagic for Python

Simple & Fast Web I/O on a Secure Blockchain

BlockMagic is an I/O Client for secure data storage and retrieval on the [Monty.Link] Blockchain. It delivers fast data I/O for web applications while ensuring security and privacy of your data.

RigoDB is a lightweight database application for Python, and it is bundled with BlockMagic to provide CRUD capabilities prior to final commits to the blockchain. This is because blockchains are immutable, meaning the data you store cannot be altered -- however, with RigoDB, you can enjoy traditional CRUD database facilities until you are ready to make a final commit to the blockchain.

Getting Started

Install BlockMagic from Pip (already bundled with RigoDB as from v2.6):

  pip2 install --upgrade block_magic

Requires: Python 2.7

Using BlockMagic

To use BlockMagic after installation via Pip, import the client in your Python2 code:

  from block_magic.blockmagic_client import *

Storing data: creating blocks and performing CRUD operations with RigoDB

You can store data on the blockchain by creating blocks. Create a different block for each of your data stores e.g. "WebDirectory", "SalesLogs", "DeviceActivity", "Logins", and so on. It's as easy as invoking the CreateBlock command:

CreateBlock("WebDirectory","contact information")  # block description is optional
CreateBlock("SalesLogs")
CreateBlock("DeviceActivity")
CreateBlock("Logins")

Running the above code generates the following success messages:

'the block [webdirectory] was registered on the blockchain'
'the block [saleslogs] was registered on the blockchain'
'the block [deviceactivity] was registered on the blockchain'
'the block [logins] was registered on the blockchain'

Once you mine (create) a block, it takes up to a minute to be registered on the blockchain. The client automatically manages the connection for you in case you want to send data immediately.

Your data is not public as it cannot be accessed from any device terminal other than the one used to create the block. Even if you use another terminal type on the same device, the data will not be available. So the communication is a closed I/O circuit.

Working with RigoDB: CRUD operations

The first thing to do when planning to save data is to create a database:

>>> RigoDB("new_database",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE"})

'CreateDBSuccess: database: DB_NAME_HERE was created'

Then we need to add a table:

>>> RigoDB("add_table",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"TABLE_NAME_HERE", "blockname":"TARGET_BLOCK_HERE"})

'CreateTableSuccess: table: TABLE_NAME_HERE was created'

Notice that in addition to specifying a table name, we had to include a block name as well: that is because every table must point to a block. When you finally commit your table, the data in the table will be transferred to the block you designate, and the table itself will cease to exist. Without committing, you can hold on to the table and the data in it as long as you wish.

Let's add some data (say, some phone records) to our table:

>>> RigoDB("new_entry",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entry":{"name":"John Egglington","phone":"1-800-212-3456","email":"john.egglington@emailserve.net"}})

'WriteTableSuccess: table: TABLE_NAME_HERE  was updated'

Note: always use lowercase when providing credentials. Also, note that you must always provide an Object (e.g. JSON document or Python dict) as your entry.

Now, let's add some more data:

>>> RigoDB("new_entry",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entry":{"name":"Monty Dimkpa","phone":"1-820-444-6718","email":"cmdimkpa@gmail.com"}})

'WriteTableSuccess: table: TABLE_NAME_HERE  was updated'
>>> RigoDB("new_entry",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entry":{"name":"Mary Tipton","phone":"1-616-420-1123","email":"mary_tipton@dowdandco.org"}})

'WriteTableSuccess: table: TABLE_NAME_HERE  was updated'

OK, let's see if we can get the data back:

>>> RigoDB("view_entries",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entryPos":"*"})

[{'phone': '1-800-212-3456', 'name': 'John Egglington', 'email': 'john.egglington@emailserve.net'}, {'phone': '1-616-420-1123', 'name': 'Mary Tipton', 'email': 'mary_tipton@dowdandco.org'}, {'phone': '1-820-444-6718', 'name': 'Monty Dimkpa', 'email': 'cmdimkpa@gmail.com'}]

That was easy enough. We can also edit and delete data:

Editing:

Let's substitute the data on the second row with another dataset:

>>> RigoDB("edit_entry",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entryPos":1, "new":{'phone': '1-222-520-4150', 'name': 'Eduardo Salazar', 'email': 'eddy_french@dowdandco.org'}})

'EditTableSuccess: table: TABLE_NAME_HERE was updated at row: 1'

Note: row numbers are zero-indexed; meaning the first row is 0 and the second is 1, and so on.

Now, let's see if the data changed:

>>> RigoDB("view_entries",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entryPos":"*"})

[{'phone': '1-800-212-3456', 'name': 'John Egglington', 'email': 'john.egglington@emailserve.net'}, {'phone': '1-222-520-4150', 'name': 'Eduardo Salazar', 'email': 'eddy_french@dowdandco.org'}, {'phone': '1-820-444-6718', 'name': 'Monty Dimkpa', 'email': 'cmdimkpa@gmail.com'}]


It sure did. How about deleting?

Deleting data:

Let's delete the 2nd row we just edited:

>>> RigoDB("delete_entry",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entryPos":1})

'EditTableSuccess: row: 1 of table: TABLE_NAME_HERE was deleted'

Let's verify:

>>> RigoDB("view_entries",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entryPos":"*"})

[{'phone': '1-800-212-3456', 'name': 'John Egglington', 'email': 'john.egglington@emailserve.net'}, {'phone': '1-820-444-6718', 'name': 'Monty Dimkpa', 'email': 'cmdimkpa@gmail.com'}]

The data is no longer there. OK so everything works. For a more comprehensive RigoDB Tutorial, go to the RigoDB Github page.

Now let's review committing this data to the blockchain.

Committing Data to the Blockchain

Prior to committing your data, you can hold it in your RigoDB tables and databases without limit. Once you commit, however, the data disappears from your local persistence and is transferred to the Blockchain.

You can either commit a table or commit a database:

  1. Committing a table

For example, let's commit our sample table:

>>> RigoDB("commit_table",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here"})

'the table: [TABLE_NAME_HERE] was committed to the blockchain and deleted from database: [DB_NAME_HERE]'

Let's see if we can still access the table:

>>> RigoDB("view_entries",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entryPos":"*"})

'TableAccessError: table not found'

So the table is gone, as expected.

Now, the table was pointing to a block called "TARGET_BLOCK_HERE", so let's quickly see if we can fetch the data from this block on the blockchain:

>>> return_one_tx("TARGET_BLOCK_HERE")

[{u'phone': u'1-800-212-3456', u'name': u'John Egglington', u'email': u'john.egglington@emailserve.net'}, {u'phone': u'1-820-444-6718', u'name': u'Monty Dimkpa', u'email': u'cmdimkpa@gmail.com'}]

So this worked perfectly.

  1. Committing a database

Committing a database effectively commits all the tables in the database, before removing it from RigoDB persistence.

Let's go ahead and just commit our test database:

>>> RigoDB("commit_database",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE"})

'the database: [DB_NAME_HERE] was committed to the blockchain and deleted from your Rigo instance'

A quick check if its still there:

>>> RigoDB("view_entries",{"dbname":"DB_NAME_HERE","dbpassword":"DB_PASSWORD_HERE", "tablename":"table_name_here", "entryPos":"*"})

'DBAccessError: could not connect to database [not found]'

OK, so that's how to use BlockMagic and RigoDB in a nutshell.

Data transport to the blockchain is fully managed by a connection manager and reporting tool that displays status in your terminal. If you have just created the block, the connection manager will keep retrying until the block is available, then it will send all the data. In general, your data is always reliably delivered to the block.

An example process output:

retrying...
{u'message': u'Ledger updated', u'code': 201} (target: http://monty.link/2iSkFewPh2/626c6f636b5f696e666f3a70686f6e653d312d3830302d3231322d33343536266e616d653d4a6f686e204567676c696e67746f6e26656d61696c3d6a6f686e2e6567676c696e67746f6e40656d61696c73657276652e6e6574)
{u'message': u'Ledger updated', u'code': 201}
{u'message': u'Ledger updated', u'code': 201}
{u'message': u'Ledger updated', u'code': 201}

Data security

BlockMagic encrypts your data as a "hash" before sending e.g.

626c6f636b5f696e666f3a70686f6e653d312d3830302d3231322d33343536266e616d653d4a6f686e204567676c696e67746f6e26656d61696c3d6a6f686e2e6567676c696e67746f6e40656d61696c73657276652e6e6574

So your data is private (encrypted) even on an open connection. Also, the client builds a "tunnel" connection to the blockchain. Any blocks created using that tunnel can only be reached via that tunnel. The tunnel is effectively a public key - private key connection between your terminal and the blockchain. This ensures that another device or user cannot access your blocks.

Retrieving data: transactions and ledgers

You can access your data as a transaction or a ledger. Transactions are stored the same way you sent them, while ledgers have been grouped by field, allowing you to access aggregated data for applications that require that format.

There are 4 convenience functions you can use to retrieve data: return_all_tx, return_one_tx, return_all_lx, and return_one_lx. As you might have guessed, these allow you to: return all transactions, return one transaction, return all ledgers and return one ledger, respectively.

For this example, we have created a block called "WebDirectory" and saved some data to it. Let's explore some scenarios for retrieving our data:

  1. store "WebDirectory" in a variable e.g.
phonebook = return_one_tx("WebDirectory")
print phonebook

Sample output:

>>> phonebook
[{u'phone': u'1-800-212-3456', u'name': u'John Egglington', u'email': u'john.egglington@emailserve.net'}, {u'phone': u'1-616-420-1123', u'name': u'Mary Tipton', u'email': u'mary_tipton@dowdandco.org'}, {u'phone': u'1-820-444-6718', u'name': u'Monty Dimkpa', u'email': u'cmdimkpa@gmail.com'}]

Notice the data was returned the way it was sent. With a ledger, it will be grouped:

phonebook = return_one_lx("WebDirectory")
print phonebook

Sample output:

>>> phonebook
{u'phone': [u'1-800-212-3456', u'1-616-420-1123', u'1-820-444-6718'], u'name': [u'John Egglington', u'Mary Tipton', u'Monty Dimkpa'], u'email': [u'john.egglington@emailserve.net', u'mary_tipton@dowdandco.org', u'cmdimkpa@gmail.com']}

Note: if you are operating on a terminal, you might see some diagnostic messages during operation. Simply ignore them as your data will always be saved to the variable you have declared.

So far, we have returned one transaction and one ledger. That's because we only have data in one block. Let's store some data in the "Logins" block, so we can demonstrate returning all transactions and all ledgers.

SampleLogins = [
  {"user":"altair444", "pass":"ojwfjefjoejfeojf8765"},
  {"user":"shazam67@y", "pass":"lacazaette686"},
  {"user":"romulusTiDer", "pass":"kljwdkwjdwdjd675"}
]
send_data("Logins",SampleLogins)

Sample output:

retrying...
{u'message': u'Ledger updated', u'code': 201} (target: http://monty.link/pZt6b4sX7/626c6f636b5f696e666f3a757365723d616c7461697234343426706173733d6f6a77666a65666a6f656a66656f6a6638373635)
{u'message': u'Ledger updated', u'code': 201}
{u'message': u'Ledger updated', u'code': 201}
{u'message': u'Ledger updated', u'code': 201}

So, we have some sample login data on the blockchain. Now's let retrieve it in our application:

logins = return_one_tx("Logins")
print logins

Output:

>>> logins
[{u'user': u'altair444', u'pass': u'ojwfjefjoejfeojf8765'}, {u'user': u'shazam67@y', u'pass': u'lacazaette686'}, {u'user': u'romulusTiDer', u'pass': u'kljwdkwjdwdjd675'}]

Additionally, since we have more than one block, we can use the return_all functions:

  1. Return all transactions
transactions = return_all_tx()
print transactions

Sample output:

>>> transactions
{u'logins': [{u'user': u'altair444', u'pass': u'ojwfjefjoejfeojf8765'}, {u'user': u'shazam67@y', u'pass': u'lacazaette686'}, {u'user': u'romulusTiDer', u'pass': u'kljwdkwjdwdjd675'}], u'webdirectory': [{u'phone': u'1-800-212-3456', u'name': u'John Egglington', u'email': u'john.egglington@emailserve.net'}, {u'phone': u'1-616-420-1123', u'name': u'Mary Tipton', u'email': u'mary_tipton@dowdandco.org'}, {u'phone': u'1-820-444-6718', u'name': u'Monty Dimkpa', u'email': u'cmdimkpa@gmail.com'}]}

Notice that this combines data from "WebDirectory" and "Logins" blocks.

  1. Return all ledgers (grouped data)
ledgers = return_all_lx()
print ledgers

Sample output:

>>> ledgers
{u'logins': {u'user': [u'altair444', u'shazam67@y', u'romulusTiDer'], u'pass': [u'ojwfjefjoejfeojf8765', u'lacazaette686', u'kljwdkwjdwdjd675']}, u'webdirectory': {u'phone': [u'1-800-212-3456', u'1-616-420-1123', u'1-820-444-6718'], u'name': [u'John Egglington', u'Mary Tipton', u'Monty Dimkpa'], u'email': [u'john.egglington@emailserve.net', u'mary_tipton@dowdandco.org', u'cmdimkpa@gmail.com']}}

Notice that the data for each block has been grouped. Nice and easy.

Benefits

BlockMagic allows you to securely and conveniently store your data in a blockchain. With RigoDB, an add-on product, you can enjoy traditional CRUD database facilities prior to immutable data commits to the blockchain. You can use BlockMagic or RigoDB seamlessly in your Python2 code while building web applications. No fancy configurations, accounts or registration required. No fees or gimmicks -- Just easy data storage and retrieval.

Connect

Send questions or comments to: cmdimkpa (at) gmail.com

Happy I/O !