User:Tom McGuire/SimpleBlockChain

From J Wiki
Jump to navigation Jump to search

Introduction

Professor Massimo Di Pierro (DePaul University) in his article "What is Blockchain?", Computing in Engineering and Science Vol. 19 No. 5 2017 https://www.computer.org/csdl/magazine/cs/2017/05/mcs2017050092/13rRUyv53Jl (Reprinted in Computing Edge April 2018)[1] provides a quick review of Blockchain technology and a small implementation example in Python. The example uses JSON library to serialize Python data into a string that can then be run through a hash to complete the block chain. It also takes advantage of Python's built in list management features. There is nothing Python specific in the implementation and making some reasonable design choices a J language implementation is straight forward.

Implementation in J

Using J's boxing feature a blockchain ledger can be implemented as a boxed list of triples. The triple just needs a timestamp, some info (which will just be a string of characters), and a calculated hash. J provides Sha256 in it's foreign conjunctions. J has a library that will serialize box structures into a JSON string.

Precision

Python has a base significant figures of about 16 digits. J allows user control over the number of significant digits displayed. Using higher significant digits will create a longer serialized string and therefore hash more characters making tampering with the blockchain more difficult.

Choice of a timestamp

J provides a foreign conjunction to get the system date and time. In Python the timestamp function provides the time in seconds from Jan 1, 1970. In J it's the number of days since 1/1/1800 with the decimal portion being the fraction of a day. The J timestamp is usable for the purpose of a timestamp. ' However, by creating a python timestamp in J the data looks very similar to the original article.

SHA 256

For this simple example SHA 256 hashing is as good as any. We aren't looking for a perfect Hash. We are just looking for something that is difficult (in terms of time and processing power) to find other string possibilities that hash to the same number.

Boxing Structure

The blockchain ledger will be a boxed list with a nested boxed triple inside of it. The boxed triple will contain a timestamp, info/data, and hash.

   3$(<'timestamp';'info';'hash')
┌─────────────────────┬─────────────────────┬─────────────────────┐
│┌─────────┬────┬────┐│┌─────────┬────┬────┐│┌─────────┬────┬────┐│
││timestamp│info│hash│││timestamp│info│hash│││timestamp│info│hash││
│└─────────┴────┴────┘│└─────────┴────┴────┘│└─────────┴────┴────┘│
└─────────────────────┴─────────────────────┴─────────────────────┘

The J code above is purely to provide a picture of the boxed structure used. While the triples essentially all look alike, the first entry is created differently to all subsequent entries. This is accomplished by using separate functions one to create the first chain entry and a second function to "add" to the chain.

To create an entry in a blockchain one needs only the previous hash. The ledger technically does not have to be complete. It is up to the distributed framework to ensure that hashes and entries get propagated. In this simple example since we are just creating a single ledger these issues do not come into play.

The J Code

require 'convert/pjson'
require 'types/datetime'

   jts =: 6!:0
   epoch =: todayno 1970 01 01
   linuxts =: 13 : '(((toDayNo y)-epoch)*24*60*60)'
   sha1 =: 1&(128!:6)

   ppq =: 9 !: 10    NB. print-precision query
   pps =: 9 !: 11    NB. print-precision set
NB. to get similar precision to standard python use:
NB. pps 16   

NB. bhash - expects a boxed triple of timestamp, info, and prevhash
NB.         as the argument
      bhash =: 3 : 0
token =: enc_pjson_ y
sha1 token
)

NB. newchain - creates the first element of the chain.
NB.            This differs from Dr. Di Pierro's implementation with 
NB.            the calculation of a hash on the first entry. 
   newchain =: 3 : 0
ts =. linuxts (6!:0 '')
< ts;y;bhash ts;y;''
)

   addchain =: 4 : 0
ts =. linuxts 6!:0 ''
prevHash =: ,> _1{. , > _1{. x
newHash =. bhash ts;y;prevHash
x,<ts;y;newHash
)

NB. verifypair - takes two consequitive ledger entries and recalculates
NB.              recalculates the hash and then sees if it matches the
NB.              original hash in the ledger. 
NB. to perform this you need the hash from first triple (2{prev) and the
NB. timestamp and info from the second triple (2{.block) and match (-:)
NB. it to the original hash (last element of second triple: 2{block)
   verifypair =: 3 : 0
'prev block' =. y
(,>2{block) -: bhash (2{.block),(2{prev)
)

NB. to verify the entire chain use:
NB.  *./ 2 verifypair\bchain 
NB. this will iterate through all the pairs of triples in the chain
NB. you also need to verify the first entry separately
verifychain =: 3 : 0
'ts info hash' =. ;{. y
(hash -: bhash ts;info;'')*. (*./2 verifypair\ y)
)

NB. Helper functions to test with
getchainidx =: 4 : 0
; x{y
)

chgchaininfo =: 4 :0
'idx info' =. x
nblock =. (<info) 1} idx getchainidx y
(<nblock) idx}bchain
)

Running the code

Using the example from the original article these are the four pieces of information hashed into the ledger:

'A found S1'
'A sells S1 to B'
'B sells S1 to C'
'C sells S1 to D'

Now in J:

   ]bchain =: newchain 'A found S1'
┌───────────────────────────────────────────────────────────────────────┐
│┌─────────────────┬──────────┬────────────────────────────────────────┐│
││1572627812.773734│A found S1│d55ba5115ad30ec33e42eb8023db45e05a6e895f││
│└─────────────────┴──────────┴────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────┘
   ]bchain =: bchain addchain 'A sells S1 to B'
┌───────────────────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────┐
│┌─────────────────┬──────────┬────────────────────────────────────────┐│┌─────────────────┬───────────────┬────────────────────────────────────────┐│
││1572627812.773734│A found S1│d55ba5115ad30ec33e42eb8023db45e05a6e895f│││1572627963.046082│A sells S1 to B│645cc52b73c83598aacbba3ee764fb0dab1969ce││
│└─────────────────┴──────────┴────────────────────────────────────────┘│└─────────────────┴───────────────┴────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────┘
   bchain =: bchain addchain 'B sells S1 to C'
   bchain =: bchain addchain 'C sells S1 to D'
   $bchain
4
   verifychain bchain
1

   NB. Now try to change the blockchain
   badchain =: (0;'E found S1') chgchaininfo bchain
   $badchain
4
   2{.badchain
┌───────────────────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────┐
│┌─────────────────┬──────────┬────────────────────────────────────────┐│┌─────────────────┬───────────────┬────────────────────────────────────────┐│
││1572627812.773734│E found S1│d55ba5115ad30ec33e42eb8023db45e05a6e895f│││1572627963.046082│A sells S1 to B│645cc52b73c83598aacbba3ee764fb0dab1969ce││
│└─────────────────┴──────────┴────────────────────────────────────────┘│└─────────────────┴───────────────┴────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────┘
   NB. changed the first entry in the badchain
   verifychain badchain
0
   NB. change an added entry of the chain
   badchain =: (2;'B sells S1 to F') chgchaininfo bchain
   2{badchain
┌───────────────────────────────────────────────────────────────────────────┐
│┌────────────────┬───────────────┬────────────────────────────────────────┐│
││1572627997.75153│B sells S1 to F│746d5facfbef7f02bb28b6c27ffe17c873524259││
│└────────────────┴───────────────┴────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────────┘
   NB. Here is what the original entry looked like
   2{bchain
┌───────────────────────────────────────────────────────────────────────────┐
│┌────────────────┬───────────────┬────────────────────────────────────────┐│
││1572627997.75153│B sells S1 to C│746d5facfbef7f02bb28b6c27ffe17c873524259││
│└────────────────┴───────────────┴────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────────┘
   NB. See if the chain verifys
   verifychain badchain
0

Conclusion

The J implementation wastes more lines with comments than it does with code. A recurring theme in most J programming, especially when arrays are involved. J's boxing structure is an excellent way to store the ledger information for this simple example. J probably has the tools necessary for a fullscale distributed blockchain implementation. Distributed instances could communicate via ZeroMQ and the ledger could be implemented in Jd, J's column based database. It won't mine Bitcoin any faster than specialized hardware platforms, but it does have the tools to go through the ledger in a code efficient manner.

Footnotes

  1. M. Pierro, "What Is the Blockchain?" in Computing in Science & Engineering, vol. 19, no. 05, pp. 92-95, 2017. doi: 10.1109/MCSE.2017.3421554 keywords: {bitcoin;contracts;peer-to-peer computing;digital signatures;authentication} url: https://doi.ieeecomputersociety.org/10.1109/MCSE.2017.3421554