Skip to content
Rici's Coding Soup. 🍜

Building a Blockchain in Swift (Part. 2)

Blockchain, Swift, Vapor3 min read

Exploring the nonce and playing with the mining service.

Before you dive in

This article is part of the series "Building a Blockchain in Swift". You can find the intro here and find the part 1 here.

The nonce

Now that we have our blockchain settled and we know how the blocks and transactions work, let’s take a look at the mining mechanism.

In our payload, we can’t really change a thing. We should maintain the block integrity, so it should be added to the chain verbatim. So what can we add to block's structure that can be tweaked for this sake?

Introducing the nonce.

This value is just a random number whose only purpose here is helping us find the "perfect" hash. The way we use it is to incrementing its value.

Mining

In a live blockchain, this algorithm isn’t part of the software. We are just putting it here for the experiment. This is the node's duty (and where all the gold relies), so it uses its own tailor-made solution.

1final class MiningService {
2
3 // 1.
4 private let blockchainDifficulty: String
5
6 init(difficulty: String) {
7 blockchainDifficulty = difficulty
8 }
9
10 // 2.
11 func mineBlock(previousBlock: Block, transactions: [Transaction]) -> Block {
12
13 let nextHeight = previousBlock.height + 1
14 print("⛏ Start mining block at height \(nextHeight)...")
15
16 // 3.
17 let block = Block(height: nextHeight, previousHash: previousBlock.hash)
18 transactions.forEach { block.add(transaction: $0) }
19
20 // 4.
21 let hash = generateHash(for: block)
22 block.hash = hash
23
24 return block
25 }
26
27 // 5.
28 func generateHash(for block: Block) -> String {
29
30 print("🔑 Finding the hash for block at height \(block.height)...")
31 var hash = block.key.toSHA1()
32
33 // 6.
34 while !hash.hasPrefix(blockchainDifficulty) {
35 block.incrementNonce()
36 hash = block.key.toSHA1()
37 print(hash)
38 }
39
40 print("🙌 Hash found! - \(hash)")
41 return hash
42 }
43}

Wow, hold on! We have too much going on there. Let’s break it down:

  1. We create the service defining the blockchain difficulty we’ll be working in. This is the amount of zeroes we’ll need to find in a hash prefix so it can be accepted by the blockchain.
  2. We set a mineBlock() method that will take the previous block and a set of transactions we want to register and then return the recently minted block.
  3. We create an instance of the next block, and then add the transactions to it.
  4. Then we need to generate the hash for this block. This will require some work from the node. Once it’s done, we return the block.
  5. The way we find the hash for the block is first to execute our SHA-1 function in the block key; and
  6. We loop over the hash value, incrementing the nonce, until we find a value that gives us a hash which is prefixed with the number of zeroes the blockchain requires.

P.S.: In this implementation I’m using a custom SHA-1 method which you can find here


You see, you don’t have any guarantee that the nonce you're using next is the right one, so there's no other way apart from trial and error, to find this value.

This is a very simple way to implement a proof-of-work consensus, but not so efficient. So feel free to explore other ways to implement yours!

The beauty behind this is that it adds entropy to this problem. It’s a fair play for all nodes in the network. Whichever node finds the hash first can mine the block.

Putting all the pieces together

Now we have enough to try to create our own blockchain. This is how we can use it:

1// Exercise1.swift
2
3// Creates the Mining Service
4let miningService = MiningService(difficulty: "00") // starting with just 2 zeroes
5
6// Generates Genesis Block
7let genesisBlock = Block(height: 0, previousHash: "0000000000000000000000000000000000000000") // 40 zeroes
8
9// Tries to find the hash for the genesis block
10genesisBlock.hash = miningService.generateHash(for: genesisBlock)
11// Once it finds the hash, create the Blockchain
12do {
13 let blockchain = try Blockchain(genesisBlock: genesisBlock)
14 print("Blockchain is ready! 🎉")
15} catch let _ {
16 print("🚫 Oh-oh! The block hash isn't valid.")
17}

If you execute the code above (you can use a Swift Playground for it), you should get some output similar to this one in your console:

1🔑 Searching the hash for block at height 0...
21CA360046CDE59C93CDAE5EC5A1A2DC7495D4A58
3E42D0BBF1E810538CBDCE382C040B599A2DDADEE
4D4D96B51564127AE292448F75603F347C5B68947
57BAC36206D7C747879F765547E7B2A2F35DC5094
6
7....
8
95AC1DF0C735FF12CA81623D5BCA5DA56553061B6
10556A5A8BA5B8EC0167B35D782F10A22A1D997661
11D0E0A2882B36B08196A0CC291532D8F213898B78
12006809C305F6F9790890E6D7C7319817F15FCEE0
13🙌 Hash found! - 006809C305F6F9790890E6D7C7319817F15FCEE0
14Blockchain is ready! 🎉

My machine needed to run the function 218 times to find a hash for the genesis block! Picture how many times it would take to find a block with today’s difficulty! 😬

Adding transactions

Now you have a blockchain you can push transactions to! Let’s try to transfer some value to people:

1// (Assumes the Exercise1.swift preceds)
2
3// Creates a new block
4let transaction = Transaction(sender: "Felipe", receiver: "Tim Cook", amount: 100)
5
6let newBlock = miningService.mineBlock(previousBlock: genesisBlock, transactions: [transaction])
7
8do {
9 try blockchain.add(block: newBlock)
10} catch let _ {
11 print("🚫 Oh-oh! The block hash isn't valid.")
12}

In your console, you should get something like this:

1⛏ Starting to mine the block at height 1...
2🔑 Searching the hash for block at height 1...
3C84DA890248ED95DF39E7AD15CACE49EA57BD6A4
4B75FE89D8125D91B6EA7B836F5C1765737741F8E
58D12099BE01B765E0EA1F2675525EEA216448E94
6E2DD2E47050DFB75C1217216EBB85E1D99A35935
7
8...
9
10C94DB820D09643D478229EA142EC0B4819503CBD
1148EAA579E1E8BA192D9F2748B30989FCE7F745C8
1243146E96DDBBC7201A1BCC9CA4C5EF588FA0219D
1300B33255769C3A5CD38E757D2C31E8CF2ACDF3C2
14🙌 Hash found! - 00B33255769C3A5CD38E757D2C31E8CF2ACDF3C2

This time the function ran for 116 times!

And that’s how your blockchain should look when printed as a JSON object:

1{
2 "blocks": [
3 {
4 "nonce": 218,
5 "previousHash": "0000000000000000000000000000000000000000",
6 "hash": "006809C305F6F9790890E6D7C7319817F15FCEE0",
7 "transactions": [],
8 "height": 0
9 },
10 {
11 "nonce": 116,
12 "previousHash": "006809C305F6F9790890E6D7C7319817F15FCEE0",
13 "hash": "00B33255769C3A5CD38E757D2C31E8CF2ACDF3C2",
14 "transactions": [
15 {
16 "sender": "Felipe",
17 "receiver": "Tim Cook",
18 "amount": 100
19 }
20 ],
21 "height": 1
22 }
23 ]
24}

Wrapping up

We’ve just written our first blockchain in Swift! 🍾

As I’ve mentioned earlier, we aren’t using the most efficient algorithm to find the hash, but that’s a great start. There's a long discussion about how sustainable the proof-of-work protocol is as well, as it demands too much energy.

That isn’t the only way to achieve consensus, though. Most advanced blockchains nowadays use protocols such as proof-of-stake (e.g. Ethereum 2.0 and Cardano), but there are many others, such as proof-of-authority, proof-of-capacity, etc.

Hope you had as much fun as I had writing this. Thanks for reading! If you have any suggestions or questions, please hit me up on Twitter!

Valeu! ✌️

© 2022 by Rici's Coding Soup. 🍜. All rights reserved.
Theme by LekoArts