Blockstack World Tour Brussels — Social Dapp workshop

Getting to know Blockstack by coding a decentralized social app

Here at Cogarius we love getting our hands dirty experimenting with new decentralized technologies. Blog post here

We are following what blockstack is building from some time now and we find their approach very interesting. Their goal is to

build an ecosystem that gives users control over their fundamental digital rights: Identity, data-ownership, privacy, and security
Needless to say it resonates with us !

How does it work ?
To put it simply blockstack enables you to build a decentralized app without the hassle of getting to know in depth the underlying blockchain protocol. Think of it as a an identity and storage layer level on top of a blockchain.

We say ‘a’ blockchain because right now for security concerns it is the bitcoin blockchain but as they have developed a virtual blockchain layer called virtual chain they could anchor the state on top of other blockchains.

So what do they put on this state ? Well, if you take a look at page 4 of the whitepaper …

an overview of the Blockstack architecture.

We can see three different layers :

  • A blockchain layer
  • A peer network combined with the blockchain layer which enables a naming system
  • A storage layer linked to the naming system giving us a zonefile that points to stored data

On the immutable blockchain layer we can see that domain names are linked to public key and storage location.

That make sense ! Thanks to those layers blockstack can provide

A serverless authentication for your application

Indeed to make the authentication secure blockstack makes extensive use of public key cryptography ( ECDSA with the secp256k1) curve as described on the schema here after. Moreover the domain name and public key is stored on a blockchain so that it makes it very hard for an attacker to modify it.

You can easily create a blockstack ID for free using the blockstack browser. It will generate random words, a seed or keychain, that will be used to generate your first indentity and the next ones. Then using that identiy you can complete the authentication process of blockstack dapps.

overview of the authentication model

The requesting application sends the Blockstack Browser an authRequest token. Once a user approves a sign in, the Blockstack Browser responds to the application with an authResponse token.

These tokens are JSON Web Tokens, and they are passed via URL query strings.

But how the public key cryptography enters into account ?

use and generation of the transit, user and app user keys in blockstack authentication workflow

Now you understand better why they say “blockstack makes extensive use of public key cryptography” !

A decentralized high-performance storage system

Blockstack has implemented a decentralized high-performance storage system called Gaia . Gaia works by hosting data in one or more existing storage systems of the user’s choice. These storage systems are typically cloud storage systems.

Blockstack applications use the Gaia storage system to store data on behalf of a user. When the user logs in to an application, the authentication process gives the application the URL of a Gaia hub. The application can then performs write operations and decrypt the stored data.

The Gaia hub authenticates write operation to a location by requiring a valid authentication token, generated by a private key authorized to write at that location.

When an application fetches a file data.txt for a given user alice.id, the lookup will follow these steps:

  1. Fetch the zonefile for alice.id, and read her profile URL from that zonefile
  2. Fetch the Alice’s profile and verify that it is signed by alice.id’s key (more on that in the DNS section)
  3. Read the application root URL (e.g. https://gaia.alice.org/) out of the profile
  4. Fetch file from https://gaia.alice.org/data.txt

Because alice.id controls her zonefile, she can change where her profile is stored, if the current storage of the profile is compromised. Similarly, if Alice wishes to change her gaia provider, or run her own gaia node, she can change the entry in her profile.

For applications writing directly on behalf of Alice, they do not need to perform this lookup. Instead, the blockstack authentication flow provides Alice’s chosen application root URL to the application. This authentication flow is also within Alice’s control, because the authentication response must be generated by Alice’s browser as described in the schema here above.

Once you authenticate a user with store_write and publish_data, you can begin to manage data for your users. Blockstack JS provides two methods getFile() and putFile() for interacting with Gaia storage. The storage methods support all file types. This means you can store SQL, Markdown, JSON, or even a custom format. But don’t worry we will give you a working example on this here below on the dapp section.

A Domain Name System

In a regular DNS (Domain Name Service) we have a mapping between a human readable domain name like cogarius.com to a computer understandable IP and we have to trust the dns servers to get the correct IP for a domain name.

Blockstack with his BNS (Blockstack Naming Service) replaces advantageously the dns servers with the blockchain and it makes sense because everybody can access the ledger. Moreover the ledger being immutable it is extremely hard to remove or update a record and get away with it.

They even use some of DNS standard like RFC 1464 for the TXT entry.

So for each action on a name or a namespace like creation, update or renew there will be a transaction on the underlying blockchain so that’s why you will need to pay some transaction fee to do so. Like in the traditional DNS you also have to pay a fee to register a domain name. Blockstack Core API has a convenient endpoint to know how much a domain name is worth, for instance if you want to register the name satoshinakamoto on the namespace id just browse https://core.blockstack.org/v1/prices/names/satoshinakamoto.id and you will get “satoshis”: 100000,”units”: “BTC” so 0.001 ฿

We understood that this DNS record allows us to map a name with an address and a zonefile.

How can we verify that ?

Let’s take this example https://core.blockstack.org/v1/names/jude.id

We got that results :

response from names endpoint of the blockstack core API

The name jude.id is therefore linked to the address 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg. We can also see the profile location in the zonefile https://raw.githubusercontent.com/jcnelson/profile/master/jude.id

If we navigate to the specified profile we find a token signed by the owner of the address and that contains more information on this profile. Tip: You can check it out by pasting it on jwt.io.

First let’s verify the zonefile_hash. It is quite simple as it requires two hashes : the first one is SHA256 and the second one is RIPEMD160. If you use a library like cryptojs you would have something like that :

cryptojs example of SHA256 and RIPEMD160 to find the zonefile hash

Which gave us the intended answer b6e99200125e70d634b17fe61ce55b09881bfafd

Now we should make sure that this hash is indeed stored on the blockchain. In the response we have the last_txid d44f72b157352fc33fa78f84d16c9e4704074c92596bb645a9b262922511f9ec

Which is actually a bitcoin transaction id. Let’s open a bitcoin explorer

https://www.blocktrail.com/BTC/tx/d44f72b157352fc33fa78f84d16c9e4704074c92596bb645a9b262922511f9ec

In the output script we have this :

OP_RETURN 69643a6a7564652e6964000000000000000000000000000000000000000000000000000000000000b6e99200125e70d634b17fe61ce55b09881bfafd

This operation is a name registration. Indeed if we take a look at how the bitcoin transaction are formatted we see that it matches the variation 2 of the wire format. Here is the format:

bitcoin wire format for name registration

Here is the data after the OP_RETURN:

6964 the magic which hex decoded give usid”

3a the operation code which hex decoded give us “:

69643a6a7564652e6964 the name that is registered which hex decoded give usjude.id

B6e99200125e70d634b17fe61ce55b09881bfafd which is our zone file hash

In the first output after the op_return we have a scriptPubkey for the owner’s address which is 16EMaNw3pkn3v6f2BgnSSs53zAKH4Q8YJg

And there you have the address field return by the blockstack core api !

Our social dapp example : Stackarius

Now that we understand better what we can do with blockstack let’s take a look at our project. You can find and play with the source code on our github. First thing first let’s talk about our application stack.

Here at Cogarius we prefer to discover errors at compilation than at runtime that’s why we chose typescript over javascript. We also like reactive application with a nice state management. Finally we don’t want to spend too much time configuring our development environment so we end up with this front stack :

  • Angular 6
  • Typescript
  • Ngrx : redux store implementation
  • Rxjs : combined with ngrx effects you got that nice reactive touch
  • Clarity : nice and slick UI framework that includes lots of angular components

And of course blockstackjs !

Features

The app is built around three main sections.

  • notes lets you list, add, update and remove notes that only you can read.
  • wall lets you add, update and remove public posts that everybody can read. In the post list you will also see all the post from the people that you have added in your contact.
  • contacts display a list of your contact and an add button that allows you to search for new contact and add it to your contact list.

We wanted to build a social app but why ?

First because we are hosting the belgium event of the blockstack world tour and our guest is the afari guys !

Then because it is those apps that hurt the most our fundamental digital rights.

Finally because it would give us the opportunity to see how we can take the best out of blockstack meaning …

We want to be able to authenticate and search for other profiles

For authentication it is quite easy as it only requires one function that will do the heavy lifting mentioned above.

To search for profile we simply use the blockstack core API and if you want to lookup one profile like the logged on we use the lookupProfile() function

We want to store and access data

Blockstack allows us to store files. Depending on your needs you can choose whether to store json, database or even plain text file. For stackarius we chose the json file. The interface is very easy as there are only two main functions cleverly named getFile() and putFile(). Note that by default putFile will encrypt the data to be written with your app private key.

To read the post written by our contact we call getFile but this time we fill the contact username in the option object. As the file structure is the same for all the users the path is easy to guess.

service to write and read from gaia

We want to store and share data to trusted parties

The idea here is to have like a private channel where you only share posts with known and trusted parties. Obviously you can’t write data into others storage. So how do you share a post with let’s say one or two of your contacts only ?

A solution would be to encrypt the post for those contacts and to put the encrypted data on your storage. We would then also need to notify these contacts that a post is waiting for us in our storage.

What key should we use ? Well actually we can, by looking at someone’s profil, see their app pubkey key. It is inside an Array called “apps” where you will find all the storage locations used by your app. The pubkey is nested inside the path. Here is an example :

“https://stackarius_cogarius_com": “https://gaia.blockstack.org/hub/19y2HkLRZAAm1kTUnZNSdenK1qEKUgmZQR/"

the pubkey in this example is : 19y2HkLRZAAm1kTUnZNSdenK1qEKUgmZQR

Why is the app pubkey in here ? In the gaia doc we can find this sentence

Access control in a gaia storage hub is performed on a per-address basis. Writes to URLs /store/<address>/<file> are only allowed if the writer can demonstrate that they control that address. This is achieved via an authentication token, which is a message signed by the private-key associated with that address.

So to be able to access the data located under the folder 19y2HkLRZAAm1kTUnZNSdenK1qEKUgmZQR I must be able to sign the token which I can since I have the app private key decoded in my locale storage after the authentication process is complete.

How can we notify the contacts ? There is a proposal to extend gaia so that it can support an inbox message here.

Otherwise a solution can be to simply check all the storage of your contacts. This solution is not very elegant as you don’t have a reactive feedback to the user and there is a lot of overload.

A less decentralized solution would be to store that notification on an external server. If you for instance use a websocket connection your dapp can subcribe to the notification and can trigger the retrieval of your posts in very reactive way.

troubleshooting

MixContent and CORS

As there is a redirection to the blockstack browser if you see the message below you have to either configure your http server cors settings to allow https://browser.blockstack.org/ or if you are in development mode on firefox for instance it only allows the mix content on 127.0.0.1 so if you are browsing localhost:4200 just replace it by 127.0.0.1:4200

failed to fecth information from blockstack browser due to cors settings

Module not found: Error: Can’t resolve ‘crypto’

Angular-cli uses a webpack.config that does not include the nodejs crypto lib.

so if you happen to have this error

ERROR in ./node_modules/blockstack/lib/keys.js

Module not found: Error: Can’t resolve ‘crypto’ in ‘node_modules/blockstack/lib’

here is how we fixed it thanks to this usefull article and GrandSchtroumpf comment

Firt install dev dependency

$ npm i -D @angular-builders/custom-webpack

modify your angular.json change the

@angular-devkit/build-angular:browser builder

to

@angular-builders/custom-webpack:browser

create a new file `webpack.config.js` under your root folder (next to package.json)

If you want to run ng serve with a custom webpack configuration (given that you performed all the above steps)

$ npm i -D @angular-builders/dev-server

Finally in angular.json in the “serve” step, replaces

_@angular-devkit/build-angular:dev-server_

by

_@angular-builders/dev-server:generic_

Conclusion

Blockstack is an interesting tech that combines the power of decentralized storage, naming system and identity thanks to the blockchain. The javascript library is clear and simple, especially for the authentication part even though there is a lot going on in the background.

Working with Blockstack allowed us to experiment with data ownership. Indeed having a true data ownership means that your app doesn’t store data into a central database but rather is allowed by the user to write to the user’s storage. And it raises some interesting challenges like how do you share data with others ? how do you notify others that you have data to share ? We pointed out some ways to achieve that in this article. Like in every project things can be improved and it is even more relevant when we are speaking about innovative tech like blockchain. We will definitely keep experimenting with blockstack as there is a lot going on and the best is yet to come :)

Made with love by the Cogarius team :) if you want to know more about what we do please visit our website.

from ideas to solutions www.cogarius.com