Skip to content

Commit 2b02404

Browse files
authored
'Hello, Blockchain!' post (#15)
1 parent 839f20d commit 2b02404

File tree

4 files changed

+223
-0
lines changed

4 files changed

+223
-0
lines changed

_data/authors.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ Drew Hamilton:
2424
name : "Drew Hamilton"
2525
avatar : "assets/images/avatars/drew.jpg"
2626
bio : "Principal Mobile Engineer - R&D"
27+
28+
Alexey Buistov:
29+
name : "Alexey Buistov"
30+
avatar : "assets/images/avatars/ab.jpeg"
31+
bio : "Solutions Architect, Crypto Enthusiast - R&D"
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
---
2+
title: "Hello, Blockchain!"
3+
excerpt: "Create a \"Hello, world!\"-style React app that reads and displays data from the Joystream blockchain"
4+
tags: Blockchain React
5+
authors:
6+
- Alexey Buistov
7+
header:
8+
teaser: /assets/images/post/people.png
9+
teaser_alt: Hello, Blockchain!
10+
category: Dev
11+
---
12+
13+
![](/assets/images/post/people.png)
14+
15+
16+
This tutorial walks you through the process of creating a very minimal "Hello, world!" - style React app that reads and displays data from the Joystream blockchain. Along the way, I comment a thing or two about scaffolding React applications, JSON-RPC APIs and about the blockhain itself.
17+
18+
19+
# Blockchain? Really?
20+
21+
It might seem a bit silly to write an introduction into blockchain in 2021, but the fact is: it wasn't before 2020, "the Corona year," that this technology appealed to me.
22+
23+
The highly centralized fintech world where I'm coming from is very very different to what blockchain is, and in way is much easier to grasp. A blockchain is a distributed software network that functions both as a digital ledger and a mechanism enabling the secure transfer of assets without an intermediary. In addition to such secure transfers, blockchain technology provides a permanent cryptographic record of transactions and a single version of the truth - a network state that is fully transparent and displayed in real time for the benefit of all participants.
24+
25+
This transparency comes at a price, though. One thing I've realised about the blockchain is that it resembles a super slow database. Why? Without "The Central Server®" or "The Master Database™," when nodes in your network are all the same, meaning structurally and architecturally there's no hierarchy at play whatsoever, how would you achieve the concensus about even such simple things as knowing your account balance?
26+
27+
If hierarchy is removed from the system design, that is, in decentralised systems, network consensus suddently becomes a very hard computer science problem known as Byzantine Consensus. I will not pretend I understand how blockchain architectures address this problem, but apparently they're very good at it. And because they're very good at it, they're also typically much less convenient to use and performant than traditional centralized systems.
28+
29+
With this intro in mind, let's jump into the code.
30+
31+
# Hacking Time
32+
33+
### Environment setup
34+
35+
If you haven't got any Node, npm, yarn installed, or in case you're a Java backend developer not knowing a thing about front-end stuff, don't worry and read on. Installing these tools on Mac via `brew` is smooth and easy process.
36+
37+
38+
First, get npm if you haven't got it already. In your Terminal app, run
39+
```
40+
brew install npm
41+
```
42+
It happened to me that the above command crashed with the error: `Error: Interrupted system call @ rb_sysopen - /usr/local/Cellar/nghttp2/1.44.0/bin/nghttp`. This error is usually caused by your antivirus software. The good news is: you don't even have to care about it. Simply go ahead and execute the exact same command several more times. After a few attempts, `npm` will install just fine.
43+
44+
45+
Instead of working from scratch, let us quickly scaffold a blank React application. For those of you who have, like me, never coded in Typescript or React, zero configuration scaffold tool called [create-react-app](https://github.com/facebook/create-react-app) is a true life-saver. Simply execute
46+
```
47+
npx create-react-app hello-blockchain-react --template typescript
48+
```
49+
50+
On first run, you will be prompted to add `create-react-app` and all its depencencies. Be patient, this process may take a while, but in the end it will give you a fully set-up runnable React application.
51+
52+
Now go to the newly created application folder and run the app:
53+
54+
```
55+
cd hello-blockchain-react && npm start
56+
```
57+
58+
Your browser should show you the welcome page. You're all set the for the most interesting part of the exercise now.
59+
60+
### Building the React Component
61+
62+
The particular blockchain we will be connecting to and reading data from is called [Joystream](https://www.joystream.org/). Joystream is a decentralized video platform with big ambitions (think Youtube with no Google involved). Being built on [Polkadot](https://polkadot.network/technology/), it requires us to install some additonal Polkadot dependencies. Here's how you do it:
63+
64+
```
65+
npm add @polkadot/api@4.2.1
66+
```
67+
Validate that the package has been installed by inspecting the file `package.json`:
68+
```
69+
less package.json | grep polkadot
70+
"@polkadot/api": "^4.2.1",
71+
```
72+
73+
Lastly, let's install custom Joystream type definitions that are used to describe data inside the blockchain.
74+
```
75+
npm add @joystream/types
76+
```
77+
Validate that the package has been installed by inspecting the file `package.json`:
78+
```
79+
less package.json | grep joy
80+
"@joystream/types": "^0.16.1",
81+
```
82+
83+
Awesome. Now it's the right time to add a custom React component to our app. We might do this from scratch, but scaffolding is way cooler, isn't it? To generate a skeleton of our Joystream component, let's run
84+
```
85+
npx generate-react-cli c Joystream
86+
```
87+
First time, the code generator tool asks you some questions to be able to self-configure itself. Keep pressing Enter to give the default answers, until the component file will get generated (plus some other stuff we are not going to use in this tutorial, like tests or styles).
88+
89+
The function component code produced by the scaffolding tool looks like this:
90+
```
91+
import React from 'react';
92+
import styles from './Joystream.module.css';
93+
94+
const Joystream = () => (
95+
<div className={styles.Joystream} data-testid="Joystream">
96+
Joystream Component
97+
</div>
98+
);
99+
100+
export default Joystream;
101+
```
102+
103+
In your browser what you'll get out of this code is just an HTML <div> with a static text, and yet there's something I'd like to highlight. What might look as an HTML snippet (lines 5-7), isn't a real HTML, but a thing called JSX. JSX is simply a syntax extension of JavaScript. It allows us to directly write HTML in React (within JavaScript code). It is easy to create a template using JSX in React, but it is not a simple template language instead it comes with the full power of JavaScript. It is faster than normal JavaScript as it performs optimizations while translating to regular JavaScript. Instead of separating the markup and logic in separated files, React uses *components* for this purpose.
104+
105+
To include our new function component into the app, we need to update the main file `App.tsx`:
106+
107+
* Import the component
108+
109+
```
110+
import Joystream from './components/Joystream/Joystream';
111+
```
112+
113+
* Place the component in the DOM by replacing the paragraph `<p>` element:
114+
115+
```
116+
<code>
117+
<Joystream/>
118+
</code>
119+
```
120+
121+
Save your edits and reload the browser. Your component text (Joystream Component) should be now visible.
122+
123+
### Accessing the blockchain API
124+
125+
Now let's go back to the function component and start hacking. Import the API client from Polkadot and custom Joystream types:
126+
127+
```
128+
import { WsProvider, ApiPromise } from "@polkadot/api";
129+
import { types } from "@joystream/types";
130+
```
131+
Then define the connection URL
132+
```
133+
const wsLocation = 'wss://rome-rpc-endpoint.joystream.org:9944'
134+
const provider = new WsProvider(wsLocation)
135+
```
136+
For the sake of this tutorial, we'll use the URL of a remote Joystream node located in Rome, Italy. Note: this doesn't mean our app would read the data from some sort of "Central Server ®" As an alternative, we could have spin up our own Joystream node on local laptop, let it get up to speed with the rest of the nodes in the network (this process is called synchronisation and takes quite some time), and read the same data from it. But one tutorial can't fit everything :) I'll show you how to do it in future installments.
137+
138+
Now let's refactor the code of the component to allow further additions
139+
```
140+
const Joystream = () => {
141+
return (
142+
<div className={styles.Joystream} data-testid="Joystream">
143+
Joystream Component
144+
</div>
145+
)
146+
};
147+
```
148+
It's just a refactoring, so functionally it stays the same. Double-check this by refreshing your browser page. What is allows us to do is to define our function components' state like this:
149+
```
150+
const [lastBlock, updateLastBlock] = useState(0)
151+
const [connected, updateConnected] = useState(false)
152+
```
153+
Note: `useState` needs to be imported, too:
154+
```
155+
import {useState, useEffect} from 'react';
156+
```
157+
And the main thing - a new React Effect that connects to the API:
158+
```
159+
useEffect(() => {
160+
ApiPromise.create({ provider, types }).then((api) =>
161+
api.isReady.then(() => {
162+
console.log(`Connected to ${wsLocation}`);
163+
api.derive.chain.bestNumber().then((finalizedHeadNumber) => {
164+
updateLastBlock(finalizedHeadNumber.toNumber())
165+
updateConnected(true)
166+
}
167+
)
168+
})
169+
);
170+
}, [lastBlock, connected]);
171+
172+
```
173+
A lot of things are going on here, but what's essential for the purpose or our exercise is to understand only the basics. The *Effect Hook* lets you perform side effects in function components. Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects.
174+
175+
Our side effect does several things:
176+
1. Instantiates the API client
177+
2. Connects to the node URL using Websocket
178+
3. Once the connection is established, it calls the API method and reads the data returned by it
179+
4. Updates the internal component state
180+
181+
All we have to do now is to take advantage of the internal state and include it in the JSX which the Joystream component produces:
182+
```
183+
return (
184+
<div className={styles.Joystream} data-testid="Joystream">
185+
{!connected? 'Connecting to blockchain...' :
186+
`Connected! Latest block is: ${lastBlock.toLocaleString()}`}
187+
</div>
188+
)
189+
```
190+
191+
Note how the front-end experience has changed. First, you see the text 'Connecting to blockchain...' because the component is busy establishing the connection (which may take a second or two), but then the text magically changes to a different one, showing the number of the last produced block that was sent by the Joystream API. Look at the code we've written so far and try to understand how does this conditional behavior work.
192+
193+
### Subscribing to updates from the API
194+
195+
What we've built so far looks good, but let us breathe a little dynamism in our app by making the last block information updated *as the blockchain produces new blocks* (on Joystream, the average time to produce one block is [six seconds](https://testnet.joystream.org/#/explorer). What's needed to achieve this is the subscription mechanism instead of a one-off API call:
196+
197+
```
198+
api.rpc.chain.subscribeNewHeads((header) => {
199+
console.log(`Chain is at block: #${header.number}`);
200+
201+
if(!connected) {
202+
updateConnected(true);
203+
}
204+
205+
if(header.number.toNumber() !== lastBlock) {
206+
updateLastBlock(header.number.toNumber());
207+
}
208+
})
209+
```
210+
211+
Since we are dealing with a subscription, we now pass a callback into the `subscribeNewHeads` function, and this callback shall be triggered on each block (header), as they are imported.
212+
213+
214+
That's it, folks. If you've enjoyed this little journey, the best way of saying 'thank you' is sending some coins to my ETH address `0xe654F6D40e2b9eBFf62b02a23129E9C81ce26a88`. By the way, I've also prepared a [Github repo](https://github.com/singulart/hello-blockchain-react) with all the code from this trail is nicely divided into several commits for easier usage. Consider checking out the [branch](https://github.com/singulart/hello-blockchain-react/tree/css-transition) where you'll find a simple CSS Transition to animate our "Hello, Blockchain!" app.
215+
216+
217+
218+

assets/images/avatars/ab.jpeg

54.4 KB
Loading

assets/images/post/people.png

412 KB
Loading

0 commit comments

Comments
 (0)