There are a lot of talks and discussions about decentralized social platforms and their importance for our society and future. These talks became more active after Facebook–Cambridge Analytica data scandal, news that Google removes ‘Don’t be evil’ from its code of conduct and unsuccessful blocking of Telegram in Russia. The problem with social platforms and messangers is obvious, but in my opinion there is no simple solution. A lot of people say that blockchain will help us to solve all issues, we just have to create messangers on a blockchain, twitter on a blockchain, telegram on a blockchain, facebook on a blockchain, etc. Sometimes it looks like everything with a blockchain becomes better (not true at all). On the one hand, it sounds very cool, it should help us to share information and knowledges without borders and censorship. But on the other hand — there are a lot of problems with blockchain scalability and throughput limits.

What

In this article I’ll show how to implement fully decentralized social platform like twitter or telegram channels for sharing information publicly, not messanger. It looks like twitter, but I see the use case like Telegram channel — best place to share some information without fear that somebody can ban your account. I am absolutely sure, that social platform should have some ways to ban accounts and hide information, but it should not be centralized, there is no one source of truth, neither the company nor the one person can not decide to ban some piece of information. It also should be social.

Another important thing is a price. It should not be free, because as we all know “If You’re Not Paying For It, You Become The Product”. But it can’t be too expensive also. For example, storing 1MB in Ethereum network costs ~$1867.78.

And very important characteristic for the platform — geographical and political decentralization. Blocking of the platform should be harder than blocking an IP range. It should not require central servers or databases, we want to make requests only to blockchain nodes.

The last, but not the least requirement for our system is speed. Sometimes it’s hard to use Twitter because of it’s slow speed, but Telegram is blazing fast, and we will try to be like Telegram, not Twitter. When we talk about a blockchain and speed it sound impossible, but we want to give best possible user experience.

How

We can use new feature of Waves Platform called Data Transactions. They are designed for another use cases — using by oracles, providing data for smart contracts or certifying authorship of a document by publishing its hash on the blockchain. Data Transactions allow to attach some key-value pairs to an address. Keys are arbitrary UTF-8 strings and are case sensitive. Each value has a data type associated with it. 4 data types are supported: boolean, integer, string, and byte array. It is impossible to delete keys, you only can rewrite the value.

The price of 1MB currently is only 1.024 WAVES or ~$5. As we need — it’s not free, but not too expensive.

Another important feature should be a decentralization and Waves fits it very good. Below you can compare geographical and political distribution of Waves Nodes and Ethereum Nodes.

Waves Nodes (data from http://dev.pywaves.org/nodes/)

Ethereum nodes (by www.ethernodes.org)

And last important requirement is speed. And Waves is really, REALLY FAST thanks to Waves NG Protocol.

Well, Waves Platform fits all our requirements very well, and now we can start implementing it. Note: Data Transactions are available only on TESTNET now. It will be activated on MAINNET on June 28 2018 07:24 UTC.

Implementation

First of all, we have to consider how we can use Data Transactions for social platform. We can store data only on users’ account, we can’t send data transactions to another users, but we can read data from another users address. It means, that we have to handle somehow the registration process. To tell the truth, there is no registration, because our social platform is more like meta-protocol using data transactions than a platform. It’s not possible to get a list of users with some key in their data transactions (unless we scan whole blockchain), so we must require to send usual transfer transaction to our central address. If user sends a transaction to the address he confirms his desire to use the platform. In this case getting users list becomes much easier: just get a list of transactions and get sender addresses.

Getting list of users of the platform

In this example we require users to send transaction with custom asset called TwitterCoin. This coin is issued on Waves Platform and can be used for filtering content or as a reward token for authors. For example, you can get TwitterCoins when other users like your message, also platform can hide users without TwitterCoins (kind of social blocking). This functionality is not implemented, but you can help with it.

Preparations

To store information in a blockchain we have to send signed by private key Data Transaction to public TESTNET nodes. It is possible to sign Data Transactions with PyWaves library, but it won’t work in a browser. Waves JavaScript library doesn’t support Data Transactions yet, so I implemented DataTransaction class in my example. Signing data with private key is little bit complicated and I’ll not describe it here, you can find the code on github. We will only use DataTransaction class to create an instance of transaction with method broadcast to send signed data to the public node. The node will send it to all known other nodes and replicate data. DataTransaction also calculates fee depending on the size of transaction.

Settings

Every user can set some information about his profile. We will provide UI to set diplay name, BIO, avatar image and profile color. When transaction will be added to the chain we expect to get from the node API an array of values like on image. We added prefix twitter. to all keys to avoid potential ambiguity in the future.

For saving data in shown way we will construct a JSON object with required parameters: sender , senderPublicKey , timestamp and data . DataTransaction class will convert each data entry before broadcasting to base64 and calculate fee depending on the size and parameter feePerKb .

Constructing Data Transaction

Note: maximum size of one value is 32 KB, so we have to split an image, if it’s size is bigger.

Tweets and retweets

We will store each users’ message as serialized JSON object. It costs us more, because of JSON special characters, but it’s flexible and gives us opportunity to save not only message, but references to another users’ tweets. Also with JSON we can change message format in the future. Messages stored as shown below:

Each message key consists of prefix — twitter , type — post , send time — {TIMESTAMP} , random generated 3 chars — {ID} . Every post in our protocol has it’s unique identifier. Inside the value (JSON object) we store message text and referene to another twitter post in case of retweet. Reference is prefixed by posts’ author address and guarantees that every post has unique identifier. Note: @ used as delimeter.

Likes and following

Following is very important, because users feed is a main part of application. Let’s use addresses as key and boolean type values — we can’t delete key, so we will change the value depending on following status. When user clicks Follow button we add new key-value pair, where key is twitter.sub.{ADDRESS} and value is true or false .

Like buttons work almost same, the only difference is in key construction rule. We will use same rule like in references — {ADDRESS}@twitter.post.{TIMESTAMP}-{ID} with prefix twitter.like.

Boolean values in Data Transactions

How it works

Every time, when user opens his feed we will request all his data entries. We can get the list of following users addresses very easy — find all keys with prefix twitter.sub. and value equals to true.

For each address in the list we have to get data entries with keys twitter.displayName , twitter.avatar.0 , …, twitter.avatar.N , twitter.bio and twitter.color . To get posts of each user we need to find all entries with keys like twitter.post.{TIMESTAMP}-{ID} .

For UI we will use React based framework Material UI Next, it is simple and looks great. Also it gives us the power of React Components. I made components MessageCard, RetweetCard, FollowButton, LikeButton independent.

You can see the demo below or try it by yourself:

Try the demo

Source codes are available on github:

What’s next?

This project is just Proof-Of-Concept and I do not recommend to use it as real product — at least blockchains are not designed for storing such amount of data. At the same time, this project can be improved with token mechanics and economics.