We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to apply for this job!

Login or register
to publish this job!

Login or register
to save this job!

Login or register
to save interesting jobs!

Login or register
to get access to all your job applications!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel 🚀.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Engineers who find a new job through Python Works average a 15% increase in salary 🚀

Blog hero image

WebAssembly to Run Blockchain Using Go

Mahmoud Fathy 1 April, 2021 | 10 min read

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 will be 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 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 to 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 the 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 blockchain.
  • chainfabric: The underlying network which binds nodes together during the mining operation.

Program-structure-blockchain-go-wasm.png

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 browser.
    • 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.

Usecase-blockchain-go-wasm.png

index.html

As for having the process running in a browser, it requires an index.html file from which the application starts.

code snippet

<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href="styles.css" media="screen" />
    <script src="wasm_exec.js"></script>
    <script>
      const go = new Go();
      WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {go.run(result.instance);});
    </script>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js" 
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
    crossorigin="anonymous"></script>

  </head>
  <body>
    <div class="w-3 container">
      <div class="w-6">
        <select onchange="changeUser(this.value)" class="w-9 color-lightblue">
            <option value="0">User👨🏻‍💻:</option>
            <option value="Alice">Alice🙍‍</option>
            <option value="Bob">Bob👨‍💼</option>
        </select>
      </div>

      <div class="w-6">
        <input type="range" min="0" max="64" value="19" class="slider" id="diffRange">
      </div>
      <div class="clear"></div>
        <button onClick="reward()" class="w-6 color-lightblue mg-top">Reward 💰</button>
        <button disabled id="BuyBtn" onClick="buyCommodity()" class="w-6 color-lightblue mg-top mg-left">
          Buy 🍎 🍌
        </button>
      <div class="clear"></div>
      <label class="w-6 mg-top">Difficulty ⚙️:</label>
      <label id="diffLabel" class="w-3 mg-top mg-left">
        
      </label>
      <div class="clear"></div>
      <label class="w-6 mg-top">Networth 💵:</label>
      <label id="networth" class="w-3 mg-top mg-left">
        
      </label>
      <div class="clear"></div>
    </div>
    <div id="blockchain-placeholder" class="w-9">
      <!-- Blockchain schematic goes here  -->
    </div>


    <script>
        // Update the current slider value (each time you drag the slider handle)
        sliderVal = function(val) {
          $("#diffLabel").html(val);
          sendSliderValToWasm(val);
        }
        $("#diffRange").on("change mousemove", function() {
          sliderVal($(this).val());
        });
        sliderVal($("#diffRange").val());
      </script>
  </body>
</html>

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 as 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.

code snippet

func RegisterCallbacks() {
	js.Global().Set("reward", js.FuncOf(reward))
	js.Global().Set("buyCommodity", js.FuncOf(buyCommodity))
	js.Global().Set("networth", js.FuncOf(networth))
	js.Global().Set("changeUser", js.FuncOf(changeUser))
	js.Global().Set("sendSliderValToWasm", js.FuncOf(sendSliderValToWasm))
}

var (
	merchant string
	price    float64
)

func changeUser(this js.Value, args []js.Value) interface{} {
	if args[0].String() != "0" {
		document := js.Global().Get("document")
		document.Call("getElementById", "BuyBtn").Set("disabled", js.ValueOf(false))
		options := document.Call("getElementsByTagName", "option")
		for i := range []int{0, 1, 2} {
			options.Index(i).Set("disabled", js.ValueOf(true))
		}
		User = args[0].String()
		// this call initializes the User's wallet hence so are the node connections
		GetWallet()
		if User == "Alice" {
			merchant = "Bob"
		} else {
			merchant = "Alice"
		}
		if merchant == "Alice" {
			price = 10
			document.Call("getElementById", "BuyBtn").Set("innerHTML", "Buy Bananas  🍌")
		} else {
			price = 20
			document.Call("getElementById", "BuyBtn").Set("innerHTML", "Buy Apples  🍎")
		}
	}
	return js.Null()
}

func buyCommodity(this js.Value, args []js.Value) interface{} {
	if User == "" {
		return js.Null()
	}
	success := GetWallet().PayTo(merchant, price)
	if !success {
		js.Global().Call("alert", "Insufficient Crypsys")
	}
	return js.Null()
}

func networth(this js.Value, args []js.Value) interface{} {
	if User == "" {
		return js.Null()
	}
	return js.ValueOf(GetWallet().Networth())
}

func reward(this js.Value, args []js.Value) interface{} {
	if User == "" {
		return js.Null()
	}
	go func() {
		GetWallet().Reward(10)
	}()
	return js.Null()
}

func sendSliderValToWasm(this js.Value, args []js.Value) interface{} {
	if User == "" {
		return js.Null()
	}
	diff, _ := strconv.Atoi(args[0].String())
	GetWallet().SetDifficulty(uint8(diff))
	return js.Null()
}

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 latter. 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 argument 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 disabled attribute for the dropdown options to true. Since the 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 number 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 the 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 consuming 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.

code snippet

// renderPage reloads elements of the page when change to wallet occurs
func RenderPage() {
	wlt := *GetWallet()
	document := js.Global().Get("document")
	chainView := (*wlt.GetBlockchain()).Draw()
	if chn := document.Call("getElementById", "chain"); chn != js.Null() {
		document.Call("getElementById", "blockchain-placeholder").Call("removeChild", chn)
	}
	document.Call("getElementById", "blockchain-placeholder").Call("appendChild", chainView)
	networthLabel := document.Call("getElementById", "networth")
	networthLabel.Set("innerHTML", wlt.Networth())
}

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.

code snippet

var NotifyListeners func()

// Wallet is the interface struct to the blockchain for the user
type Wallet struct {
	username string
	chain    *Blockchain
}

// NewWallet creates a Wallet struct
func NewWallet(username string) Wallet {
	return Wallet{username, NewBlockchain()}
}

// SetDifficulty sets the difficulty value for the PoW done by block mining
func (wlt Wallet) SetDifficulty(diff uint8) {
	SetDifficulty(diff)
}

// Reward transfers amt to owner of wallet from coinbase
func (wlt *Wallet) Reward(amt float64) {
	tr := Transaction{"Coinbase", wlt.username, amt}
	wlt.chain.RequestTransaction(tr)
}

// Networth traverses the blockchain to calculate user's balance
func (wlt Wallet) Networth() float64 {
	// Calculate transaction To "username" minus From "username"
	var netsum float64
	for _, blk := range (*wlt.chain).GetChain() {
		var trnsxn = blk.GetTransaction()
		if trnsxn.To == wlt.username {
			netsum = netsum + trnsxn.Amount
		}
		if trnsxn.From == wlt.username {
			netsum = netsum - trnsxn.Amount
		}
	}
	return netsum
}

// PayTo transfers amt to the username specified from the owner of this wallet
func (wlt *Wallet) PayTo(username string, amt float64) bool {
	if wlt.Networth() < amt {
		return false
	}
	tr := Transaction{wlt.username, username, amt}
	wlt.chain.RequestTransaction(tr)
	return true
}

// GetBlockchain temp func used only for testing
func (wlt Wallet) GetBlockchain() *Blockchain {
	return wlt.chain
}

In the first line NotifyListeners is a callback that 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 initiates 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 an 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.

code snippet

var wg sync.WaitGroup

func main() {
	wg.Add(1)
	web.RegisterCallbacks()
	wg.Wait()
}

Right at 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 are 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 through localhost: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 the first instance and pick Bob on the second one, now both wallets are initiated.
  • On Bob's instance: click Reward.
    • For a new block to be created mining is taking time.

Bob-instance-reward1-bob.png

  • This mining problem is solved by Bob's miner giving a nonce value of 1453337, this is explained thoroughly in part 2.
    • A new block is created showing the transaction, his networth increases by 10 while Alice is still having no crypsys.

Alice-instance-reward1-bob-blockchainView.png

  • 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.

Bob-instance-buyBananas1-blockchainView.png

  • 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. Alice-instance-buyApples1.png
    • 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.

Alice-instance-buyApples1-blockchainView.png

  • 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 into it together in the next part of this article.

All code you can find in my repository

Originally published on www.codementor.io

    Elixir
    phoenix
    React
    Python
    Elm
    DevOps

Related Issues

cosmos / gaia
  • Open
  • 0
  • 0
  • Intermediate
  • Go
cosmos / gaia
  • Started
  • 0
  • 2
  • Intermediate
  • Go
cosmos / ibc
  • Open
  • 0
  • 0
  • Intermediate
  • TeX
cosmos / ibc
cosmos / ibc
  • Started
  • 0
  • 1
  • Intermediate
  • TeX
viebel / klipse-clj
viebel / klipse-clj
  • Started
  • 0
  • 4
  • Intermediate
  • Clojure
viebel / klipse
  • Started
  • 0
  • 1
  • Intermediate
  • Clojure
viebel / klipse
  • 1
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • Started
  • 0
  • 4
  • Intermediate
  • Clojure
  • $80

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through Python Works average a 15% increase in salary.

Start with GitHubStart with Stack OverflowStart with Email