Last active
January 8, 2019 15:58
-
-
Save harshvishu/e6e0353e77588f8a0835306f31088e48 to your computer and use it in GitHub Desktop.
Swift-Blockchain-Node
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Blockchain: Chain { | |
// MARK: - Properties | |
... | |
var nodes: Set<String> | |
// MARK: - Initializers | |
init() { | |
... | |
nodes = Set() | |
// Create the genesis block | |
self.newBlock(previous_hash: "1", proof: 100) | |
} | |
// MARK: - Methods | |
... | |
// Generate a globally unique address for this node | |
var node_identifier: String { | |
return ProcessInfo().globallyUniqueString.replacingOccurrences(of: "-", with: "") | |
} | |
/** | |
Add a new node to the list of nodes | |
- Parameter address: Address of node. Eg. 'http://192.168.0.5:5000' | |
*/ | |
func registerNode(address: String) -> Bool { | |
let options = ClientRequest.parse(address) | |
for option in options { | |
if case let ClientRequest.Options.hostname(host) = option, !host.isEmpty { | |
self.nodes.insert(host) | |
return true | |
} | |
} | |
print("Invalid URL") | |
return false | |
} | |
/** | |
Determine if a given blockchain is valid | |
- Parameter chain: A blockchain | |
- returns: True if valid, False if not | |
*/ | |
func validChain(_ chain: [Block]) -> Bool { | |
var last_block = chain[0] | |
var current_index = 1 | |
while current_index < chain.count { | |
let block = chain[current_index] | |
print("\(last_block)") | |
print("\(block)") | |
print("\n----------\n") | |
// Check the hash of the block is correct | |
let last_block_hash = self.hash(block: last_block) | |
if block.previous_hash != last_block_hash { | |
return false | |
} | |
// Check that the Proof of Work is correct | |
if !self.validProof(last_proof: last_block.proof, proof: block.proof) { | |
return false | |
} | |
last_block = block | |
current_index += 1 | |
} | |
return true | |
} | |
/** | |
This is our Consensus Algorithm, it resolves conflicts | |
by replacing our chain with the longest one in the network. | |
- returns: True if our chain was replaced, False if not | |
*/ | |
func resolveConflicts() -> Bool { | |
let neighbours = self.nodes | |
var new_chain: [Block]? | |
// We're only looking for chains longer than ours | |
var max_length = self.chain.count | |
// Grab and verify the chains from all the nodes in our network | |
for node in neighbours { | |
let semaphore = DispatchSemaphore(value: 0) | |
struct ResponseData: Decodable { | |
let chain: [Block] | |
let length: Int | |
} | |
let request = RestRequest(method: .get, url: "http://\(node):5000/chain") | |
request.responseObject { (response: RestResponse<ResponseData>) in | |
switch response.result { | |
case .success(let response_data): | |
let length = response_data.length | |
let chain = response_data.chain | |
if length > max_length && self.validChain(chain) { | |
max_length = length | |
new_chain = chain | |
} | |
case .failure(let error): | |
print(error) | |
} | |
semaphore.signal() | |
} | |
_ = semaphore.wait(timeout: .distantFuture) | |
} | |
// Replace our chain if we discovered a new, valid chain longer than ours | |
if let new_chain = new_chain { | |
self.chain = new_chain | |
return true | |
} | |
return false | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment