A Blockchain Framework in Swift — Part 1
My name is Nick, and I’m a Senior Mobile Engineer at TWG. I’ve been a building mobile apps @ TWG for over 3 years now.
TWG’s mission is to help startups and enterprises design and build software that transforms their business. We are committed to helping our clients understand blockchain, not because it’s a popular subject, but because we understand the opportunity that decentralized platforms can provide.
I recently took the opportunity to do a deep-dive into the world of blockchain. Given that there are plenty of esoteric principles behind blockchain, as part of the process, I decided to apply my knowledge towards becoming a Certified Bitcoin Professional (CBP).
While the certification is exclusively for Bitcoin, I discovered that the Bitcoin Developer Reference contained an abundance of general concepts that apply to a lot of other blockchain technologies and projects… not just Bitcoin.
I used a Swift playground to develop some of the technical concepts I was reading, and the playground quickly became something I returned to often during my review.
As my blockchain playground became more and more comprehensive, I thought that the creation of a blockchain framework would be helpful to teach others, as well as for the Swift community to build upon.
This article marks the first part in a three part series of articles exploring the creation of the framework, as well as some interesting applications built on top of it.
It assumes at least an intermediate-level understanding of Swift, a good understanding of creating dynamic frameworks, and linking that all together with Xcode.
The purpose of the framework should be to provide flexibility and utility to developers. We shouldn’t particularly limit the type of data that can be stored in the blockchain — for instance, by building the notion of “Transactions” into it.
We also don’t want to create something so complicated that it’s unapproachable. Especially since there are still a lot of developers learning about blockchain development concepts for the first time. For those reasons, I’m going to separate the architecture with those points in mind.
Here’s a high-level stack diagram outlining how components can be layered on top of the framework we’ll build:
The “SwiftChain” framework will provide the basic functions of a blockchain. Any additional features one might want to put into the blockchain, like:
- Node & peer discovery
Should all be extracted to another layer (labelled “Blockchain Node” in the diagram above). This will allow you to use the blockchain framework for many different purposes.
Basic Project Set Up
Let’s get started by setting up our project structure. We’re going to have a few different Xcode projects all contained within a workspace.
Create a new directory for your projects:
mkdir blockchain-swift; cd blockchain-swift
Open up Xcode, and select:
File > New > Project
Select the macOS tab at the top, and then select Cocoa Framework. This will be the used to create the blockchain framework.
In the next dialog, enter “SwiftChain” for the product name, and select “next”. Navigate to where you created your empty directory, and select “create”.
Xcode will set up a new empty framework project for you, and now we’re almost ready to develop our first model!
In the file navigator, create a new group under the existing “SwiftChain” group named “Models”. In that group, create a new Swift file named “Block.swift”.
We’ll start by defining the fundamental piece of the blockchain — the block.
A block is merely a container that holds any data we want to put in it. What makes the block special for a blockchain, is that it has a unique combination of properties:
index of the block indicates the position of this block in the sequence of blocks.
nonce is short for “number used once”. It’s an arbitrary number that can be incremented to affect the resultant hash value for the block.
hashValue property represents a unique sequence of characters that identifies and uniquely represents the content of the block.
previousHash property is like the
hashValue property above, but it’s the key piece to the blockchain —it is what connects this block to all other blocks before it.
timestamp property allows us to determine when this block was created.
data property is also important — it’s what we are trying to store on the blockchain to begin with!
Go ahead and define the following structure and properties in your block file:
Note the deliberate use of
struct. By defining our block as a
struct, we limit the opportunity for a developer to accidentally modify (or unintentionally hold references to) the block, or properties inside the block once it’s been added to the blockchain. Since a
struct is a value type in Swift, that means we won’t be working with references to an object in memory. This works out well for us, because by definition, blocks are immutable once they’ve been added to the blockchain.
Block to conform to the Codable protocol allows the model to be encoded and decoded to various formats. This will be very useful at the
Blockchain Node layer, illustrated in the stack diagram above.
Next, we want to create our initializer for the
Block object. Go ahead and add the following to your block:
This initializer is responsible for putting properties from various places into the right spot for the new block.
In order to create a new block object, we need: the last block in the blockchain, the data we want to put into it, and the difficulty it should be mined at. I will explain block difficulty later on.
Blocks are going to continuously be added to a list, with the
previousHash property of the new block referencing the value of
hashValue property of the previous block. This diagram illustrates the connection between the properties:
previousHash in the genesis block points to… nothing? The genesis block is special — there isn’t anything that comes before it, so we can use the static
defaultHash property as the value of
previousHash (see line 8).
The last thing we want to do for now in
Block.swift, is to make our object Equatable. Swift will attempt to automatically synthesize the equality method for us. Since it’s preferable to have control over equality for our blocks, we’ll do it manually:
We still have some work to do on the block, but let’s come back to that after we‘ve taken a look at the blockchain class.
The blockchain class is the interface for adding new data to our blockchain, and also helps govern the rules of how it behaves. Let’s start working on it by creating a new file called
Blockchain.swift, just as you did before.
The interface to our blockchain should be fairly simple. Remember, they are immutable, and therefore, we don’t have to worry about any complicated removal algorithms. This leaves us with the following requirements:
- A way to add data to the blockchain
- Some mechanism to compute hashes for all of our blocks
- A way to control & adjust the difficulty of the mining process
Blockchain.swift, we need to define a class that will control our blockchain. Since we’re building a framework that other developers might want to extend, we’ll give the blockchain class an
open access level.
Above, I’ve defined some properties in the class that will be used to form our blockchain.
blocks property is an array that will hold all of the block objects that get created when we insert data into the blockchain. I’ve chosen to store blocks using an array because it will help keep the complexity of the framework relatively low. By contrast, we could use a linked list data structure, but that would require that we provide an implementation of one, and that we switch our
Block object to be a
class, rather than a
lastBlock properties are computed properties that relate to our
blocks array. They represent the length of our blockchain (by returning the count of elements), and last block object in the array, respectively.
blockTime property corresponds to the amount of time (in seconds) between new blocks being added to the blockchain. I’ve arbitrarily chosen 3 seconds for our implementation, but it’s important to note that this value varies greatly for other blockchains.
currentDifficulty property is going to be used to determine what an acceptable hash value looks like. Difficulty is a measure of how hard it is to compute a hash value for the current block, and is typically implemented using leading zeros in the block hash values.
The zeros are somewhat arbitrary, you could use any character or pattern that scales with some difficulty value… but having any number of them in a row means that whichever hashing algorithm is being used must compute hashes until one is found that satisfies the target difficulty.
Now that we have our basic properties defined, we can add initializers and a lazily computed genesis block. As we saw before, the genesis block is the first block in the blockchain, and should always be present.
I’ve created two initializers, one that creates a genesis block with no data, and one that allows a developer to seed some data into the blockchain. This could be anything, from a newspaper headline, to an encoded set of validation rules for future blocks.
You might notice a warning on line 7 of the snippet above — this is expected, since we’re going to be later adding a mutating function to the block object we created earlier.
Additional Project Configuration
We’ve come to the point where we need to implement the concept of “mining” a block.
The mining process involves running computations for a specific set of values that will yield a hash for the block corresponding to the current difficulty level. In order to compute that value, we need a set of hash functions that we can select from.
Fortunately, there is a collection of Swift implementations for these functions in a library called CryptoSwift. This library supports MD5, SHA1, SHA2 and SHA3 hash functions, along with variants for each.
Rather than get involved with package managers, we’ll simply download the source code to the library and create a workspace where we can link the
CryptoSwift library to our own:
Unpack the contents of the downloaded source, and move it to your
blockchain-swift folder that we created earlier:
mv krzyzanowskim-CryptoSwift-526d5e9 ~/dev/blockchain-swift/CryptoSwift
Now, you should have two folders in your blockchain-swift directory. One named “SwiftChain”, and one named “CryptoSwift”.
Create a new workspace by selecting:
File > New > Workspace, and save it in the root level of your
Xcode should open up a empty window for your new workspace.
You can either drag the project file from the
SwiftChain framework, or use the + icon in the bottom-left corner of the project navigator.
Find the project files for each library, and add them.
NOTE: You will need to close any other Xcode windows you have open that for the
If everything has been set up correctly, you should have a workspace with two projects in it that looks like this:
Now, we can link the
CryptoSwift framework to our own, by selecting the
SwiftChain project in the project navigator:
The last step is to switch to
Block.swift and add the following code to the top:
Back to the Block
It’s time to start implementing our mining methods. Let’s first make our lives a little simpler by adding some helpers to the block object:
key property allows us to quickly choose what fields we wish to include in the block’s overall hash.
computeHash() function wraps the SHA256 algorithm that we’ll be using to generate our hashes, and returns a
String for the hash value. You might be wondering why I created a whole method to do this. What would the framework be without providing flexibility for developers? We’ll eventually allow the algorithm that gets used in this method to be configurable.
Finally, we can add the mining method! To your block, add a mutating function
mine(at difficulty: Int)...
Let’s break this method down.
The first line calculates a string of
0 characters that corresponds to the provided difficulty value. This will be used to check if our hash satisfies the target difficulty.
The next section computes the hash value of the data that’s been set on this block. It’s important that we do this before computing the overall hash for the block, since the
key property we defined earlier includes the
Finally, the last section computes an initial hash value, and if that value doesn’t have a prefix of
difficultyPrefix defined earlier, continue doing so until it does. Notice that we’re incrementing the
nonce property. If we didn’t do that, we’d end up with the same hash value in every iteration of the loop, and it’d never terminate! The
nonce is responsible for making sure that doesn’t happen.
Time to Mine Blocks
Now that we have a way to mine a block, we can switch back to our
Blockchain class and create a function that allows us to add data to our blockchain.
First, we need to call
mine() on block objects we’ve previously created. Add the line:
After the lazily initialized
genesisBlock is created. Then, add the line:
init(data: Data) method.
Time to Add Data
Now that we’ve got our genesis block being mined when an instance of a
Blockchain class is created, we need to create an interface so we can add more data to it! Add the following to your
There’s nothing overly-complicated going on here; we create a new block from the data provided, mine it, and append it to our list of blocks!
Difficulty and Distributed Computing
You might have noticed that I skimmed over how
currentDifficulty was determined when we first created the
Blockchain class. I think that deserves a bit of an explaination.
It’s entirely possible to use a blockchain on one device to store data and generate hash values for it.
But why would you want to?
The idea of a blockchain becomes powerful when you start imagining multiple nodes, each maintaining copies of important data and validating the work done by other nodes.
Imagine the scenario where you have lots of computers all running the mining algorithm we wrote above. The fastest ones to compute a SHA256 hash would always finish first. Additionally, as more computing power is added to a distributed blockchain, the rate at which blocks are added to the chain increases.
So, in order to keep the rate at which blocks are produced constant, we need to somehow make the SHA256 algorithm take a variable amount of time to run. If the network hashrate is very high, it should take longer to complete. If the hashrate is low, it should take less time to complete. Enter, the difficulty adjustment.
For our own difficulty implementation, we’ll use a simplified approach. If the time between when blocks are added to the blockchain is faster than the
blockTime setting we specified, increase the difficulty by 1. If it takes longer than the
blockTime, well decrease it by 1.
Here’s what the updated difficulty looks like:
Framework Finishing Touches
The last steps to make this framework ready to use, are to allow it to be compiled for macOS, iOS, tvOS, and watchOS. Rather than recreating instructions on how to do that here, I’d suggest instead that you read PromiseKit’s blog post for creating Multiplatform, Single-scheme Xcode Projects.
Once you have the project configured for each architecture, you’re at a point where you can sit back and relax, because you’ve just created a blockchain framework in Swift!
If you want to test out your new framework, create a macOS or iOS application in your workspace and link & import the
SwiftChain framework to it.
I quickly did this to make sure everything checked out, and used the debugger to examine the blockchain.
let chain = Blockchain()
chain.addBlock(data: "test data!".data(using: .utf8)!)
This gives us:
(lldb) po blocks
▿ 2 elements
▿ 0 : Block
- index : 0
- nonce : 0
- previousHash : "0000000000000000000000000000000000000000000000000000000000000000"
- dataHash : ""
- difficulty : 0
- hashValue : "7cf21033fe72a1fdf0381c7804761874e7881790a7dc280fe03334d4fd13802f"
- time : 547690088.66048205
- data : nil
▿ 1 : Block
- index : 1
- nonce : 0
- previousHash : "7cf21033fe72a1fdf0381c7804761874e7881790a7dc280fe03334d4fd13802f"
- dataHash : "dd530c2ff028eae19960e984e1a929f4ae5feb5baeb246889ea95a3e2c11da3d"
- difficulty : 0
- hashValue : "42ffe74af9fc63a7b4281477c188f10f638fc5cfcf7d11b09099e640475f438f"
- time : 547690160.63899505
▿ data : Optional<Data>
▿ some : 10 bytes
- count : 10
▿ pointer : 0x000060c0000334d0
- pointerValue : 106377750197456
▿ bytes : 10 elements
- 0 : 116
- 1 : 101
- 2 : 115
- 3 : 116
- 4 : 32
- 5 : 100
- 6 : 97
- 7 : 116
- 8 : 97
- 9 : 33
That’s it for part one of this series! We’ve created a basic Blockchain framework from the ground up that allows us to add any data we want to it.
Watch for upcoming entries as I further develop the SwiftChain framework, and extend it into a “Blockchain Node”, and then build an application on top of it!
I’m now maintaining and providing downloadable source code with documentation for SwiftChain.
Feel free to open pull requests, issues, and help improve the library!
You can find the code at: https://github.com/ndizazzo/SwiftChain