The abstract below has been taken from my MSc thesis paper QuantiTeam: Blockchain architecture as a medium to verify collaborative work. The full paper is available in PDF format here.
The ability to work proficiently in collaboration with others is highly valued within a large number of social contexts. Yet, a person’s ability to do so is scarcely quantifiable in any meaningful way. The goal of this project was therefore to examine the feasibility of constructing a system which can verify and quantify collaborative work. The project was set in the specific context of attempting to solve student disengagement, as the larger concept arose from this concrete problem.
The project attempts to provide a high level of potential for true verification and quantification of collaborative data by utilising a distributed data structure known as a blockchain. Following an analysis of how the proposed system could be structured in terms of interactions between a client and the blockchain, an API was constructed to provide as much functionality as was feasible within the time available. Additionally, a simple client-side mobile application was developed to showcase the API’s functionality in a concrete manner.
While the project falls short of establishing a manner to truly verify and quantify collaborative work with a distributed blockchain, it demonstrates that such an endeavour is certainly feasible given more time and expertise in the topic area, thus providing a basis for future work to create a bona fide system for verification and quantification of team work.
The following dependencies are required to run a local development instance of QuantiTeam's Tendermint blockchain:
docker
(& docker-machine
on OSX). eris
provides a wrapper and toolchain around the Tendermint blockchain and is used extensively. To install the project's Node.js dependencies, ensure your present working directory (pwd
) is quantiteam/chain
and run:
npm install
First, let's move into QuantiTeam's API directory with the following command:
cd chain
Creating a local dev simplechain
:
. ./simplechain.sh
in the repository's root directory, which should start logging the chain's activities after setup. Assuming we now have a functioning simplechain
instance, let's boot it up and configure some local environment variables. In the repo's root directory run the following two shell scripts:
. ./chain-up.sh; . ./envsetup.sh
We can easily verify whether the simplechain
instance is running as expected by following its log output:
npm run chainlog
Now that we have a local development chain running which we can interact with, let's spin up the chain service which will act as our API router to interface with the local chain itself.
First, let's compile and deploy our Solidity smart contracts in the contracts
directory:
# `$addr` should be defined from previously running `envsetup.sh`
npm run compile -- $addr
Anytime a change is made to the smart contracts, compile
should be run to deploy these changes to the running simplechain
instance.
Next, we'll want to run QuantiTeam's test suite to ensure everything is working as expected:
npm test
This should also provide a coverage report once all unit tests have run.
The chain service itself can be built & booted simply with:
npm run build
Anytime a change is made to the node server, build
should be run as it builds a new service container via docker
and replaces it with the previous one via eris
.
Please refer to package.json
for more detailed insights into which shell commands each NPM script executes.
QuantiTeam's API exposes the following HTTP endpoints:
/user/taken
req.body.username
is already taken. Returns a boolean. {
username: string
}
{
isTaken: boolean
}
/user/signup
req.body.form
. Returns the new User
contract's hex address.{
form: {
name: string,
email: string,
username: string,
password: string
}
}
{
address: string // hex address
}
/user/login
req.body.form
. Returns isValid
boolean to signify validity of credentials, and a user
object if the login was successful. Additionally a team
object is returned if the user is part of a team.{
form: {
username: string,
password: string
}
}
{
isValid: boolean,
user: {
name: string,
username: string,
score: string,
teamname?: string,
email?: string,
address?: string
},
team: {
name: string,
score: number;
members: Array<User>,
founderUsername: string,
founderAddress: string, // hex address
address?: string
}
}
Note
user
& team
props will be null
if isValid === false
.team
prop will automatically be null if the user is not part of a team./user/profile/:username
req.params.username
. Returns a profile
object./user/profile/johndoe
{
profile: {
name: string,
username: string,
score: string,
teamname?: string,
email?: string,
address?: string
}
}
/tasks/:username
req.params.username
. Returns an array of Task
-type objects. Returns an empty array if :username
param has no tasks associated with it./tasks/johndoe
{
data: Array<Task>
}
/task
req.body.task
for the username in req.body.username
. Returns a boolean indicating whether a previously existing task was overwritten, along with the task's hex address.{
username: string,
task: {
id: string,
title: string,
desc: string,
reward: string,
complete: string,
status: "To Do" || "Completed" // enum
participants: Array<string>,
creator: string,
token: string,
createdAt: number // unix timestamp
}
}
{
isOverwrite: boolean,
taskAddr: string
}
/task/completed/:token
req.params.token
as completed. Returns a boolean indicating whether marking the task was successful./task/completed/xyz123
{
success: boolean
}
/team/taken/:teamname
req.params.teamname
is already taken. Returns a boolean indicating whether the team name is already taken or not./team
req.body.form
. Returns the new team's hex address in the blockchain and a boolean indicating whether the team was successfully linked to it's founder in the blockchain.{
form: {
name: string,
founderUsername: string,
founderAddress: string, // hex address
createdAt: number // unix timestamp
}
}
{
address: string, // hex address
linkSuccess: boolean
}
/team/:teamname
req.params.teamname
. Returns a Team
-type object./team/myteamname
{
name: string,
score: number,
members: Array<User>,
founderUsername: string,
founderAddress: string,
address: string // hex address
}
/team/add-member
req.body.form
. Returns a boolean indicating whether the passed username was successfully linked to the team, along with an indicator of whether the username actually exists.{
form: {
username: string,
teamname: string,
teamAddress: string // hex address
}
}
{
isTaken: boolean,
username: string,
linkSuccess: boolean
}
/upload
- Upload a task related file via multipart/form-data
.To shut down the local chain and the docker-machine
instance, simply run:
. ./chain-down.sh