WebAssembly to run blockchain using Go
Blockchain is a technology with countless applications and a great potential that is not yet fully utilized. It is an ordered list of blocks that are chained together, hence dubbed the name blockchain. One crucial feature it possesses is that blocks of the blockchain are added via consensus of the nodes building that chain. As for the fact that these blocks are created mainly to store information, that way it can be looked at as a distributed database that is run by a swarm of nodes in which consensus algorithms are provided for this swarm. In order to allow adding blocks as entries to that database in a secure and non-repudiable manner so these entries are ensured to be valid without the need of a central authority to impose that. One method to achieve this consensus is providing Proof of Work (PoW) as it takes place by requiring the nodes to undergo an exhaustive computation in which one node solely should not be able to finish. More details on blockchain and its implementation is presented later in part 2 of this article.
Golang
Golang (Go) shows up as a worthy candidate programming language, suited to run a blockchain across nodes implemented in a Decentralized Application (DApp). Its performance metrics are comparable to high performing languages like C, C++ and Rust but Go being an easy to learn and to use without sacrificing performance, puts it up an edge over them(at least for this article).
Webassembly
In order to run this DApp written in Go you need to compile it as a console application. But this would have been the case if we did not have webassembly (luckily we have it). Webassembly is a compilation target for this code to enable us run the DApp in a web browser and feel natural while interacting with it.
In this article
This article walks you through the code for a blockchain DApp running over websocket. It is shown here how to use the underlying blockchain operations with javascript to be presented on a web page. In part 2 we go through the implementation of the blockchain itself.
Program structure
The program is structured according to the figure below.
- web: UI components and event callbacks provided for user.
- wallet: Abstracting blockchain operations to very basic buy and reward operations.
- blockchain: Blockchain operations implemented here, it is worth noting that wallet belongs to Go package blockhain.
- chainfabric: The underlying network which binds nodes together during the mining operation.
Usecase scenario
- There are two users Alice and Bob, each one does the following:
- Suppose Alice opens the web browser and navigates to the application.
- First she identifies herself by picking "Alice" from a dropdown menu.
- She is seeing a window in which she can undergo operations with currency, let us call this unit currency
crypsys
. - Then she clicks
Reward
which leads her balance to add up 10 more crypsys. - Once she is having sufficient amount of crypsys, she decides to buy apples from Bob.
- The blockchain is shown as a sequence of blocks on the web broswer.
- Each operation reward/buy done triggers the blockchain to be updated and rerendered on the web browser.
- On the other hand Bob is following similar steps as Alice and he shares the same blockchain view that she is viewing.
index.html
As for having the process running in a browser, it requires an index.html file from which the application starts.
The head of the index file includes the two first consecutive scripts which are essential to run the Go program as a webassembly resource on the browser. The wasm_exec.js is included as is, since there is no need to change that file while the second script fetches the main.wasm file compiled as a target from the main.go program to run it. The jquery source included is not essential for webassembly but for the sake of easier life I included it. This also shows that we can definitely use js frameworks side by side with webassembly. UI componenets are being laid out within the <body>
selector like we do with plain html. Javascript functions registered as events on html elements like <button>
and <select>
are implemented in web/actions.go.
The actions.go file is the "bridge" that links underlying blockchain operations written in Go and its execution within the browser via webassembly.
The last script at the end of <body>
describes the behaviour of the slider and the javascript callback is also implemented in web/actions.go.
actions.go
In web/actions.go all the js functions called in index.html are implemented.
As shown all the functions in Go have the same signature to map to their respective javascript functions in index.html regardless of the arguments or return type of the later. In the first line I create a function to map javascript functions in index.html into relevant Go functions that are implemented in this file. In the second line the first arguemnt of Set()
points at the javascript function named reward
. While the second arguemnt is constructing a javascript function from the Go function reward
declared in line 59.
Whilst changeUser()
first checks if the choice coming from the dropdown is either Alice or Bob. Then it enables the Buy button in line 17 by setting the disabled
attribute to false. Similarly it toggles the disable attribute for the dropdown options to true. Since user is not allowed to be changed again once being set for the first time. Hence the User
variable is set to the value coming from the dropdown in line 22 as that sets the owner of the wallet to that User
. In lines 31-35, the Buy button is being customized according to which user has been picked. For instance if the User
equals "Alice"
, then Buy button's action is to buy apples for price of 20 crypsys.
Function buyCommodity()
invokes the wallet to pay the price of the commodity to the merchant. In which both merchant
and price
have been set priorly in the changeUser()
function call.
networth()
invokes the wallet to check the amount of crypsys the wallet's owner is having. It returns the value of networth as a javascript value which is then viewed in index.html. reward()
grants 10 crypsys to the user out from thin air, that is not how things work in real world. But it is a way to inject crypsys in this scenario as being implemented.
sendSliderValToWasm()
passes the value of the slider from index.html unto diff
variable which holds the value of mining difficulty. The bigger this value is the harder the mining problem becomes, which in turn leads to comsuming more time in order to add a new block to the blockchain.
renderer.go
RenderPage()
makes the page dynamic by reloading page elements according to changes undergone on the blockchain.
First I get the user's wallet in order to get the blockchain and the networth balance of the user later. In line 5 chainView
is a div element including other dom elements needed to draw the wallet's blockchain. In line 9 chainView
is appended into the blockchain-placeholder
in index.html. The networth label of index.html is also updated in lines 11.
wallet.go
Wallet struct is a wrapper around the blockchain operations, it mainly acts as an abstraction over the blockchain transactions.
In the first line NotifyListeners
is a callback which is called right after any mutation takes place in the blockchain which in turn requires a change in the user's UI. The struct contains the username and a pointer to the Blockchain in which it wraps. It is worth noting that golang does not provide a dedicated constructor syntax for its structs. Hence Wallet
instance is created by calling (constructor-like) function NewWallet()
as Go programmer usually resort to that way to implement a "constructor".
Networth()
traverses the blockchain to find the username of the wallet in the transactions recorded in the blockchain. It calculates his networth by subtracting the transactions initiated from her/him from the transactions forwarded to her/him.
Functions PayTo
and Reward
are wrappers around the blockchain's RequestTransaction
which initiates the process of creating a new block with the corresponding transaction. Reward
intiates the transaction from username "Coinbase" as for the sake of this article that user reflects the extra crypsys added into the "cryrpsy-economy" hence it can provide endless amount of crypsys if it needs to. PayTo
transfers crypsys from either Alice or Bob to the other as it also checks that the payer possesses adequate amount of crypsys before invoking the transaction.
main.go
This file is the compilation entry-point for the application in which RegisterCallbacks()
is invoked which is defined in actions.go that belongs to Go package web
.
Right on the beginning a WaitGroup
variable is declared so that the application does not terminate at the end of main()
. Hence the application continues running to respond to user's inputs accordingly which is being captured by calling RegisterCallbacks()
.
Let's run it !
- First navigate to root directory of main.go and compile it to webassembly.
GOARCH=wasm GOOS=js go build -o main.wasm main.go
- Run
node tracker.js
, this to establish communication among application instances. - Duplicate the application folder to later run another instance of the application.
- Run
http-server
on both root directories of main.wasm to be served throughlocalhost:port
.
miner-dapp-wasm beber$ http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8080
miner-dapp-wasm-2 beber$ http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8082
- Type both URLs on two tabs of any web browser to open two instances of the application.
- Pick Alice on first instance and pick Bob on second one, now both wallets are initiated.
- On Bob's instance: click
Reward
. - For a new block to be created mining is taking time.
- This mining problem is solved by Bob's miner giving a nonce value of 1453337, this is explained thoroughly on part 2.
- A new block is created showing the transaction, his networth increases by 10 while Alice is still having no crypsys.
- Data presented by each block:
crypsys from -> crypsys to: amount crypsys |
Hash of previous Block |
Nonce |
Hash of this Block |
- Alice also shares the same blockchain data despite that she was not involved in the last transaction.
- Now Bob decides to buy bananas from Alice.
-
His networth becomes 0 because he paid all of his 10 crypsys for the bananas (unwise move Bob !).
-
After few random buy and reward operations Alice buys apples from Bob.
-
This time Alice is alerted that the nonce was mined by Bob despite that she initiated that operation. In this case the chainfabric notified Alice's miner to stop mining once the nonce was solved by Bob.
- Now her networth is 0 as all she had before invoking that buy was 20 crypsys which is the price for Bob's apples.
Hopefully you are excited to add webassembly to your projects after skimming through this article and you get a feel of how blockchain looks like until delving in to it together in the next part of this article.
All code you can find in my repository