Skip to content
Permalink
Browse files

Merge pull request #4 from nevstad/feature/nio

Feature/nio
  • Loading branch information
nevstad committed Jun 18, 2019
2 parents 6db3329 + c92677b commit 229e61429a7d9adfeb5d835bee9f75fc1c8f8d2f
@@ -11,11 +11,12 @@ let package = Package(
targets: ["BlockchainSwift"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0")
],
targets: [
.target(
name: "BlockchainSwift",
dependencies: []),
dependencies: ["NIO"]),
.testTarget(
name: "BlockchainSwiftTests",
dependencies: ["BlockchainSwift"]),
@@ -6,7 +6,6 @@
//
import Foundation
import os.log

public class Blockchain: Codable {
// Coin specifics, stolen from Bitcoin
@@ -32,10 +31,10 @@ public class Blockchain: Codable {
}

/// The blockchain
public private(set) var blocks: [Block] = []
public var blocks: [Block] = []

/// Proof of Work Algorithm
public private(set) var pow = ProofOfWork(difficulty: 3)
public var pow = ProofOfWork(difficulty: 3)

/// Unspent Transaction Outputs
/// - This class keeps track off all current UTXOs, providing a quick lookup for balances and creating new transactions.
@@ -76,11 +75,9 @@ public class Blockchain: Codable {
/// Updates UTXOs when a new block is added
/// - Parameter block: The block that has been added, whose transactions we must go through to find the new UTXO state
public func updateSpendableOutputs(with block: Block) {
os_log("pre: %s", type: .debug, utxos.debugDescription)
for transaction in block.transactions {
updateSpendableOutputs(with: transaction)
}
os_log("post: %s", type: .debug, utxos.debugDescription)
}

/// Updates UTXOs when a new block is added
@@ -141,4 +138,15 @@ public class Blockchain: Codable {
return (sent: sent, received: received)
}

/// Calculates the circulating supply
/// - At any given block height, the circulating supply is given by the sum of all black rewards up to, and including, that point
public func circulatingSupply() -> UInt64 {
let blockHeight = UInt64(blocks.count)
if blockHeight == 0 {
return 0
}
return (1...blockHeight)
.map { Coin.blockReward(at: $0-1) }
.reduce(0, +)
}
}
@@ -45,7 +45,7 @@ public struct Transaction: Codable, Serializable {
}

public static func coinbase(address: Data, blockValue: UInt64) -> Transaction {
let coinbaseTxOutPoint = TransactionOutputReference(hash: "spazzy".data(using: .utf8)!, index: 0)
let coinbaseTxOutPoint = TransactionOutputReference(hash: Data(), index: 0)
let coinbaseTxIn = TransactionInput(previousOutput: coinbaseTxOutPoint, publicKey: address, signature: Data())
let txIns:[TransactionInput] = [coinbaseTxIn]
let txOuts:[TransactionOutput] = [TransactionOutput(value: blockValue, address: address)]
@@ -76,3 +76,4 @@ extension Transaction: CustomStringConvertible {
return (from: from, to: to, amount: amount, change: change)
}
}

@@ -12,7 +12,8 @@ public typealias KeyPair = (privateKey: SecKey, publicKey: SecKey)

public final class Keygen {
private static let keychainLabelPrefix = "BlockchainSwift Wallet: "
private static let keychainAppTag = "BlockchainSwift".data(using: .utf8)!
private static let keychainAppTagPublic = "BlockchainSwift Public Key".data(using: .utf8)!
private static let keychainAppTagPrivate = "BlockchainSwift Private Key".data(using: .utf8)!

/// Attempts to generate a random ECDSA key-pair
public static func generateKeyPair(name: String, storeInKeychain: Bool = false) -> KeyPair? {
@@ -24,13 +25,14 @@ public final class Keygen {
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: storeInKeychain
kSecAttrIsPermanent as String: storeInKeychain,
kSecAttrApplicationTag as String: keychainAppTagPrivate
],
kSecPublicKeyAttrs as String: [
kSecAttrIsPermanent as String: false
kSecAttrIsPermanent as String: storeInKeychain,
kSecAttrApplicationTag as String: keychainAppTagPublic
],
kSecAttrLabel as String: keychainLabelPrefix + name as CFString,
kSecAttrApplicationTag as String: keychainAppTag
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(keyGenParams as CFDictionary, &error),
@@ -50,7 +52,7 @@ public final class Keygen {
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
kSecAttrKeySizeInBits as String: 256,
kSecAttrLabel as String: keychainLabelPrefix + name as CFString,
kSecAttrApplicationTag as String: keychainAppTag
kSecAttrApplicationTag as String: keychainAppTagPrivate
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateWithData(privateKeyData as CFData,
@@ -63,7 +65,7 @@ public final class Keygen {
}
return (privateKey: privateKey, publicKey: publicKey)
}

/// Attempts to generate an ECDSA key-pair from the sepcified privateKey hex
/// - Parameter data: The private key hex
public static func generateKeyPair(name: String, privateKeyHex: String, storeInKeychain: Bool = false) -> KeyPair? {
@@ -79,10 +81,10 @@ public final class Keygen {

/// Fetches an existing Wallet key-pair from the keychain, if it exists
/// - Parameter name: The name of the wallet
static func loadKeyPairFromKeychain(name: String) -> KeyPair? {
public static func loadKeyPairFromKeychain(name: String) -> KeyPair? {
let getQuery: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: keychainAppTag,
kSecAttrApplicationTag as String: keychainAppTagPrivate,
kSecAttrLabel as String: keychainLabelPrefix + name as CFString,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnRef as String: false
@@ -95,17 +97,54 @@ public final class Keygen {
return (privateKey: privateKey, publicKey: publicKey)
}

/// Fetches the available key-pair names from the keychain
public static func avalaibleKeyPairsNames() -> [String] {
let getQuery: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: keychainAppTagPrivate,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnAttributes as String: true,
kSecReturnRef as String: false,
kSecMatchLimit as String: 999
]
var item: CFTypeRef?
let status = SecItemCopyMatching(getQuery as CFDictionary, &item)
guard status == errSecSuccess else { return [] }
let privateKeys = item as! Array<CFDictionary>
var keyPairNames = [String]()
for keyDict in privateKeys {
let dict = keyDict as! Dictionary<String, Any>
let label = dict[kSecAttrLabel as String] as! String
guard label.hasPrefix(keychainLabelPrefix) else {
continue
}
keyPairNames.append(String(label.dropFirst(keychainLabelPrefix.count)))
}
return keyPairNames
}

/// Clears existing Wallet key-pair, if it exists
/// - Parameter name: The name of the wallet
public static func clearKeychainKeys(name: String) {
let deleteQuery: [String: Any] = [
/// - Returns: true if both keys associated with the named wallet existed and were deleted, otherwise false
@discardableResult
public static func clearKeychainKeys(name: String) -> Bool {
let deletePublicKeyQuery: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrLabel as String: keychainLabelPrefix + name as CFString,
kSecAttrApplicationTag as String: keychainAppTagPublic,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnRef as String: true
]
let deletePrivateKeyQuery: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: keychainAppTag,
kSecAttrLabel as String: keychainLabelPrefix + name as CFString,
kSecAttrApplicationTag as String: keychainAppTagPrivate,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnRef as String: true
]
SecItemDelete(deleteQuery as CFDictionary)
let statusPublic = SecItemDelete(deletePublicKeyQuery as CFDictionary)
let statusPrivate = SecItemDelete(deletePrivateKeyQuery as CFDictionary)
return statusPublic == errSecSuccess && statusPrivate == errSecSuccess
}
}

This file was deleted.

This file was deleted.

0 comments on commit 229e614

Please sign in to comment.
You can’t perform that action at this time.