From 0e911a82767cc8aca7375e69bb2fb4f5e7143084 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 12:25:18 -0600 Subject: [PATCH 01/21] set up genesis block --- Pipfile.lock | 57 ++++++++++++++++++++---------------- basic_block_gp/blockchain.py | 17 ++++++++--- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index da56139b..3839443f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "36d1480b2857d3ca47d87e44b63f4bb1c3ba85e9fba71a9389c6f8161f5edd29" + "sha256": "1cfc261928838be069088d094d13b664d7ff98667a8a9b432e94c3241ab5ad6c" }, "pipfile-spec": 6, "requires": { @@ -18,10 +18,10 @@ "default": { "certifi": { "hashes": [ - "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", - "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" ], - "version": "==2019.6.16" + "version": "==2019.11.28" }, "chardet": { "hashes": [ @@ -39,18 +39,18 @@ }, "flask": { "hashes": [ - "sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856", - "sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1" + "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", + "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" ], "index": "pypi", - "version": "==0.12.2" + "version": "==1.1.1" }, "idna": { "hashes": [ - "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", - "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" ], - "version": "==2.6" + "version": "==2.8" }, "itsdangerous": { "hashes": [ @@ -61,10 +61,10 @@ }, "jinja2": { "hashes": [ - "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", - "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" + "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250", + "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49" ], - "version": "==2.10.1" + "version": "==2.11.1" }, "markupsafe": { "hashes": [ @@ -72,13 +72,16 @@ "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", @@ -95,31 +98,33 @@ "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" ], "version": "==1.1.1" }, "requests": { "hashes": [ - "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", - "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" ], "index": "pypi", - "version": "==2.18.4" + "version": "==2.22.0" }, "urllib3": { "hashes": [ - "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", - "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", + "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" ], - "version": "==1.22" + "version": "==1.25.8" }, "werkzeug": { "hashes": [ - "sha256:865856ebb55c4dcd0630cdd8f3331a1847a819dda7e8c750d3db6f2aa6c0209c", - "sha256:a0b915f0815982fb2a09161cb8f31708052d0951c3ba433ccc5e1aa276507ca6" + "sha256:169ba8a33788476292d04186ab33b01d6add475033dfc07215e6d219cc077096", + "sha256:6dc65cf9091cf750012f56f2cad759fa9e879f511b5ff8685e456b4e3bf90d16" ], - "version": "==0.15.4" + "version": "==1.0.0" } }, "develop": { @@ -132,11 +137,11 @@ }, "flake8": { "hashes": [ - "sha256:859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661", - "sha256:a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8" + "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb", + "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca" ], "index": "pypi", - "version": "==3.7.7" + "version": "==3.7.9" }, "mccabe": { "hashes": [ diff --git a/basic_block_gp/blockchain.py b/basic_block_gp/blockchain.py index 54ead5c1..95591bbe 100644 --- a/basic_block_gp/blockchain.py +++ b/basic_block_gp/blockchain.py @@ -31,13 +31,20 @@ def new_block(self, proof, previous_hash=None): """ block = { - # TODO + 'index': len(self.chain) + 1, + 'timestamp': time(), + 'transactions': self.current_transactions, + 'proof': proof, + 'previous_hash': previous_hash or self.hash(self.chain[-1]) + } # Reset the current list of transactions - # Append the chain to the block + self.current_transactions = [] + # Append the block to the chain + self.chain.append(block) # Return the new block - pass + return block def hash(self, block): """ @@ -127,7 +134,9 @@ def mine(): @app.route('/chain', methods=['GET']) def full_chain(): response = { - # TODO: Return the chain and its current length + # Return the chain and its current length + 'chain': blockchain.chain, + 'length': len(blockchain.chain) } return jsonify(response), 200 From 7588a42a6d0752bafef3eec5b5c09d3158c74bb4 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 12:34:15 -0600 Subject: [PATCH 02/21] (feat) hashing works --- basic_block_gp/blockchain.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/basic_block_gp/blockchain.py b/basic_block_gp/blockchain.py index 95591bbe..a0caf0af 100644 --- a/basic_block_gp/blockchain.py +++ b/basic_block_gp/blockchain.py @@ -63,8 +63,12 @@ def hash(self, block): # or we'll have inconsistent hashes # TODO: Create the block_string + stringObject = json.dumps(block, sort_keys=True) + blockString = stringObject.encode() # TODO: Hash this string using sha256 + rawHash = hashlib.sha256(blockString) + hexHash = rawHash.hexdigest() # By itself, the sha256 function returns the hash in a raw string # that will likely include escaped characters. @@ -73,7 +77,7 @@ def hash(self, block): # easier to work with and understand # TODO: Return the hashed block string in hexadecimal format - pass + return hexHash @property def last_block(self): @@ -136,7 +140,7 @@ def full_chain(): response = { # Return the chain and its current length 'chain': blockchain.chain, - 'length': len(blockchain.chain) + 'length': len(blockchain.chain), } return jsonify(response), 200 From a501e5b8c2b150fe5dcdc2d0a01668ad1cb6ac52 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 12:55:34 -0600 Subject: [PATCH 03/21] (feat) guided project mvp --- basic_block_gp/blockchain.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/basic_block_gp/blockchain.py b/basic_block_gp/blockchain.py index a0caf0af..dff13999 100644 --- a/basic_block_gp/blockchain.py +++ b/basic_block_gp/blockchain.py @@ -62,11 +62,9 @@ def hash(self, block): # We must make sure that the Dictionary is Ordered, # or we'll have inconsistent hashes - # TODO: Create the block_string stringObject = json.dumps(block, sort_keys=True) blockString = stringObject.encode() - # TODO: Hash this string using sha256 rawHash = hashlib.sha256(blockString) hexHash = rawHash.hexdigest() @@ -91,9 +89,12 @@ def proof_of_work(self, block): in an effort to find a number that is a valid proof :return: A valid proof for the provided block """ - # TODO - pass - # return proof + blockString = json.dumps(block, sort_keys=True) + proof = 0 + while self.valid_proof(blockString, proof) is False: + proof += 1 + + return proof @staticmethod def valid_proof(block_string, proof): @@ -107,9 +108,10 @@ def valid_proof(block_string, proof): correct number of leading zeroes. :return: True if the resulting hash is a valid proof, False otherwise """ - # TODO - pass - # return True or False + guess = f"{block_string}{proof}".encode() + guessHash = hashlib.sha256(guess).hexdigest() + + return guessHash[:3] == "000" # Instantiate our Node @@ -125,11 +127,16 @@ def valid_proof(block_string, proof): @app.route('/mine', methods=['GET']) def mine(): # Run the proof of work algorithm to get the next proof + proof = blockchain.proof_of_work(blockchain.last_block) + + previousHash = blockchain.hash(blockchain.last_block) + newBlock = blockchain.new_block(proof, previousHash) # Forge the new Block by adding it to the chain with the proof response = { - # TODO: Send a JSON response with the new block + 'block': newBlock, + } return jsonify(response), 200 From 8381fe0cceeab3005485e07ca9725f2c5173c944 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 14:17:07 -0600 Subject: [PATCH 04/21] (bump) copied blockchain code to client folder --- client_mining_p/blockchain.py | 138 +++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 2 deletions(-) diff --git a/client_mining_p/blockchain.py b/client_mining_p/blockchain.py index a0a26551..925184cf 100644 --- a/client_mining_p/blockchain.py +++ b/client_mining_p/blockchain.py @@ -1,2 +1,136 @@ -# Paste your version of blockchain.py from the basic_block_gp -# folder here +import hashlib +import json +from time import time +from uuid import uuid4 + +from flask import Flask, jsonify, request + + +class Blockchain(object): + def __init__(self): + self.chain = [] + self.current_transactions = [] + + # Create the genesis block + self.new_block(previous_hash=1, proof=100) + + def new_block(self, proof, previous_hash=None): + """ + Create a new Block in the Blockchain + + A block should have: + * Index + * Timestamp + * List of current transactions + * The proof used to mine this block + * The hash of the previous block + + :param proof: The proof given by the Proof of Work algorithm + :param previous_hash: (Optional) Hash of previous Block + :return: New Block + """ + block = { + 'index': len(self.chain) + 1, + 'timestamp': time(), + 'transactions': self.current_transactions, + 'proof': proof, + 'previous_hash': previous_hash or self.hash(self.chain[-1]) + + } + + # Reset the current list of transactions + self.current_transactions = [] + # Append the block to the chain + self.chain.append(block) + # Return the new block + return block + + def hash(self, block): + """ + Creates a SHA-256 hash of a Block + + :param block": Block + "return": + """ + stringObject = json.dumps(block, sort_keys=True) + blockString = stringObject.encode() + + rawHash = hashlib.sha256(blockString) + hexHash = rawHash.hexdigest() + return hexHash + + @property + def last_block(self): + return self.chain[-1] + + def proof_of_work(self, block): + """ + Simple Proof of Work Algorithm + Stringify the block and look for a proof. + Loop through possibilities, checking each one against `valid_proof` + in an effort to find a number that is a valid proof + :return: A valid proof for the provided block + """ + blockString = json.dumps(block, sort_keys=True) + proof = 0 + while self.valid_proof(blockString, proof) is False: + proof += 1 + + return proof + + @staticmethod + def valid_proof(block_string, proof): + """ + Validates the Proof: Does hash(block_string, proof) contain 3 + leading zeroes? Return true if the proof is valid + :param block_string: The stringified block to use to + check in combination with `proof` + :param proof: The value that when combined with the + stringified previous block results in a hash that has the + correct number of leading zeroes. + :return: True if the resulting hash is a valid proof, False otherwise + """ + guess = f"{block_string}{proof}".encode() + guessHash = hashlib.sha256(guess).hexdigest() + + return guessHash[:6] == "000000" + + +# Instantiate our Node +app = Flask(__name__) + +# Generate a globally unique address for this node +node_identifier = str(uuid4()).replace('-', '') + +# Instantiate the Blockchain +blockchain = Blockchain() + + +@app.route('/mine', methods=['GET']) +def mine(): + proof = blockchain.proof_of_work(blockchain.last_block) + + previousHash = blockchain.hash(blockchain.last_block) + newBlock = blockchain.new_block(proof, previousHash) + + response = { + 'block': newBlock, + + } + + return jsonify(response), 200 + + +@app.route('/chain', methods=['GET']) +def full_chain(): + response = { + # Return the chain and its current length + 'chain': blockchain.chain, + 'length': len(blockchain.chain), + } + return jsonify(response), 200 + + +# Run the program on port 5000 +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) From e3dddc3973b27235ec39fe84f15b673361f1242b Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 15:32:55 -0600 Subject: [PATCH 05/21] (feat) mining server accepts and verifies correct proof --- client_mining_p/blockchain.py | 84 +++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/client_mining_p/blockchain.py b/client_mining_p/blockchain.py index 925184cf..337053f2 100644 --- a/client_mining_p/blockchain.py +++ b/client_mining_p/blockchain.py @@ -12,7 +12,7 @@ def __init__(self): self.current_transactions = [] # Create the genesis block - self.new_block(previous_hash=1, proof=100) + self.new_block(previous_hash=-1, proof=0) def new_block(self, proof, previous_hash=None): """ @@ -35,7 +35,6 @@ def new_block(self, proof, previous_hash=None): 'transactions': self.current_transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.chain[-1]) - } # Reset the current list of transactions @@ -63,20 +62,20 @@ def hash(self, block): def last_block(self): return self.chain[-1] - def proof_of_work(self, block): - """ - Simple Proof of Work Algorithm - Stringify the block and look for a proof. - Loop through possibilities, checking each one against `valid_proof` - in an effort to find a number that is a valid proof - :return: A valid proof for the provided block - """ - blockString = json.dumps(block, sort_keys=True) - proof = 0 - while self.valid_proof(blockString, proof) is False: - proof += 1 - - return proof + # def proof_of_work(self, block): + # """ + # Simple Proof of Work Algorithm + # Stringify the block and look for a proof. + # Loop through possibilities, checking each one against `valid_proof` + # in an effort to find a number that is a valid proof + # :return: A valid proof for the provided block + # """ + # blockString = json.dumps(block, sort_keys=True) + # proof = 0 + # while self.valid_proof(blockString, proof) is False: + # proof += 1 + + # return proof @staticmethod def valid_proof(block_string, proof): @@ -93,8 +92,16 @@ def valid_proof(block_string, proof): guess = f"{block_string}{proof}".encode() guessHash = hashlib.sha256(guess).hexdigest() - return guessHash[:6] == "000000" + return guessHash[:2] == "00" + @staticmethod + def valid_proof_block(block, proof): + properties = [block.get("index", None), block.get("timestamp", None), block.get("transactions", None), block.get("proof", None), block.get("previous_hash", None)] + if len([x for x in properties if x is not None]) != 5: + print("invalid block structure") + return False + blockString = json.dumps(block, sort_keys=True) + return Blockchain.valid_proof(blockString, proof) # Instantiate our Node app = Flask(__name__) @@ -106,19 +113,34 @@ def valid_proof(block_string, proof): blockchain = Blockchain() -@app.route('/mine', methods=['GET']) +@app.route('/mine', methods=['POST']) def mine(): - proof = blockchain.proof_of_work(blockchain.last_block) - - previousHash = blockchain.hash(blockchain.last_block) - newBlock = blockchain.new_block(proof, previousHash) - - response = { - 'block': newBlock, - - } - - return jsonify(response), 200 + jsonStr = request.data.decode("utf-8") + incomingMinedBlock = json.loads(jsonStr) + newProof = incomingMinedBlock.get("proof", None) + newID = incomingMinedBlock.get("id", None) + if newProof is None or newID is None: + return jsonify({"error": "Invalid proof info"}), 400 + newID = int(newID) + newProof = int(newProof) + + if blockchain.last_block["index"] != newID: + return jsonify({"error": "Block already solved"}), 401 + if Blockchain.valid_proof_block(blockchain.last_block, newProof): + # successful = add new block and return message indicating success + previousHash = blockchain.hash(blockchain.last_block) + newBlock = blockchain.new_block(newProof, previousHash) + response = { + "status": "success", + "block": newBlock + } + return jsonify(response), 200 + else: + response = { + "status": "failure", + } + return jsonify(response), 401 + @app.route('/chain', methods=['GET']) @@ -131,6 +153,10 @@ def full_chain(): return jsonify(response), 200 +@app.route('/lastblock', methods=['GET']) +def lastBlock(): + return jsonify(blockchain.last_block), 200 + # Run the program on port 5000 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) From 81cd12e81ddb5387a88a74af9f619128b5d727f4 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 16:09:08 -0600 Subject: [PATCH 06/21] (feat) client now mines and arbitrarily tracks its own coins in memory --- client_mining_p/blockchain.py | 9 +++----- client_mining_p/miner.py | 41 ++++++++++++++++++++++++++--------- client_mining_p/my_id.txt | 2 +- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/client_mining_p/blockchain.py b/client_mining_p/blockchain.py index 337053f2..0e52480f 100644 --- a/client_mining_p/blockchain.py +++ b/client_mining_p/blockchain.py @@ -92,7 +92,7 @@ def valid_proof(block_string, proof): guess = f"{block_string}{proof}".encode() guessHash = hashlib.sha256(guess).hexdigest() - return guessHash[:2] == "00" + return guessHash[:6] == "000000" @staticmethod def valid_proof_block(block, proof): @@ -118,14 +118,11 @@ def mine(): jsonStr = request.data.decode("utf-8") incomingMinedBlock = json.loads(jsonStr) newProof = incomingMinedBlock.get("proof", None) - newID = incomingMinedBlock.get("id", None) - if newProof is None or newID is None: + clientID = incomingMinedBlock.get("id", None) + if newProof is None or clientID is None: return jsonify({"error": "Invalid proof info"}), 400 - newID = int(newID) newProof = int(newProof) - if blockchain.last_block["index"] != newID: - return jsonify({"error": "Block already solved"}), 401 if Blockchain.valid_proof_block(blockchain.last_block, newProof): # successful = add new block and return message indicating success previousHash = blockchain.hash(blockchain.last_block) diff --git a/client_mining_p/miner.py b/client_mining_p/miner.py index 8e211b88..271e8b71 100644 --- a/client_mining_p/miner.py +++ b/client_mining_p/miner.py @@ -3,6 +3,8 @@ import sys import json +import time +import random def proof_of_work(block): @@ -13,7 +15,14 @@ def proof_of_work(block): in an effort to find a number that is a valid proof :return: A valid proof for the provided block """ - pass + blockString = json.dumps(block, sort_keys=True) + proof = 0 + startTime = time.time() + while valid_proof(blockString, proof) is False: + proof = int(random.random() * 100000000) + totalTime = time.time() - startTime + print(f"last proof took {totalTime} seconds") + return proof def valid_proof(block_string, proof): @@ -27,7 +36,9 @@ def valid_proof(block_string, proof): correct number of leading zeroes. :return: True if the resulting hash is a valid proof, False otherwise """ - pass + guess = f"{block_string}{proof}".encode() + guessHash = hashlib.sha256(guess).hexdigest() + return guessHash[:6] == "000000" if __name__ == '__main__': @@ -43,9 +54,11 @@ def valid_proof(block_string, proof): print("ID is", id) f.close() + coins = 0 + # Run forever until interrupted while True: - r = requests.get(url=node + "/last_block") + r = requests.get(url=node + "/lastblock") # Handle non-json response try: data = r.json() @@ -56,15 +69,23 @@ def valid_proof(block_string, proof): break # TODO: Get the block from `data` and use it to look for a new proof - # new_proof = ??? + new_proof = proof_of_work(data) + print(f"new_proof {new_proof}") # When found, POST it to the server {"proof": new_proof, "id": id} post_data = {"proof": new_proof, "id": id} r = requests.post(url=node + "/mine", json=post_data) - data = r.json() - - # TODO: If the server responds with a 'message' 'New Block Forged' - # add 1 to the number of coins mined and print it. Otherwise, - # print the message from the server. - pass + try: + data = r.json() + except ValueError: + print("Error: Non-json response") + print("Response returned:") + print(r) + status = data.get("status", None) + if status is not None: + if status == "success": + coins += 1 + else: + print("block already solved") + print(f"my coins: {coins}") diff --git a/client_mining_p/my_id.txt b/client_mining_p/my_id.txt index 757227a3..2d7f4af8 100644 --- a/client_mining_p/my_id.txt +++ b/client_mining_p/my_id.txt @@ -1 +1 @@ -your-name-here +michael \ No newline at end of file From 925c57885ce8de89bd2488511c985fcf2433780d Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 16:19:43 -0600 Subject: [PATCH 07/21] (feat) refactored for modularity --- client_mining_p/miner.py | 64 +++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/client_mining_p/miner.py b/client_mining_p/miner.py index 271e8b71..3cc32980 100644 --- a/client_mining_p/miner.py +++ b/client_mining_p/miner.py @@ -41,6 +41,40 @@ def valid_proof(block_string, proof): return guessHash[:6] == "000000" +def getLastblock(): + r = requests.get(url=node + "/lastblock") + # Handle non-json response + try: + data = r.json() + except ValueError: + print("Error: Non-json response") + print("Response returned:") + print(r) + return None + + return data + +def submitProof(new_proof): + # When found, POST it to the server {"proof": new_proof, "id": id} + post_data = {"proof": new_proof, "id": id} + + r = requests.post(url=node + "/mine", json=post_data) + try: + data = r.json() + except ValueError: + print("Error: Non-json response") + print("Response returned:") + print(r) + status = data.get("status", None) + if status is not None: + if status == "success": + return True + else: + print("block already solved") + return False + else: + return False + if __name__ == '__main__': # What is the server address? IE `python3 miner.py https://server.com/api/` if len(sys.argv) > 1: @@ -58,34 +92,16 @@ def valid_proof(block_string, proof): # Run forever until interrupted while True: - r = requests.get(url=node + "/lastblock") - # Handle non-json response - try: - data = r.json() - except ValueError: - print("Error: Non-json response") - print("Response returned:") - print(r) + data = getLastblock() + if data is None: break - # TODO: Get the block from `data` and use it to look for a new proof new_proof = proof_of_work(data) - print(f"new_proof {new_proof}") # When found, POST it to the server {"proof": new_proof, "id": id} post_data = {"proof": new_proof, "id": id} - r = requests.post(url=node + "/mine", json=post_data) - try: - data = r.json() - except ValueError: - print("Error: Non-json response") - print("Response returned:") - print(r) - status = data.get("status", None) - if status is not None: - if status == "success": - coins += 1 - else: - print("block already solved") - print(f"my coins: {coins}") + success = submitProof(new_proof) + if success: + coins += 1 + print(f"my coins: {coins}") From 4e266ad471c17534ad4ffa65f5affd9ff0ea1349 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 16:36:50 -0600 Subject: [PATCH 08/21] (feat) miner now checks in periodically to make sure the block its working on is not already solved --- client_mining_p/miner.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/client_mining_p/miner.py b/client_mining_p/miner.py index 3cc32980..8816fa78 100644 --- a/client_mining_p/miner.py +++ b/client_mining_p/miner.py @@ -7,7 +7,7 @@ import random -def proof_of_work(block): +def proof_of_work(block, iterations): """ Simple Proof of Work Algorithm Stringify the block and look for a proof. @@ -16,13 +16,11 @@ def proof_of_work(block): :return: A valid proof for the provided block """ blockString = json.dumps(block, sort_keys=True) - proof = 0 - startTime = time.time() - while valid_proof(blockString, proof) is False: + for i in range(iterations): proof = int(random.random() * 100000000) - totalTime = time.time() - startTime - print(f"last proof took {totalTime} seconds") - return proof + if valid_proof(blockString, proof): + return proof + return None def valid_proof(block_string, proof): @@ -92,11 +90,13 @@ def submitProof(new_proof): # Run forever until interrupted while True: - data = getLastblock() - if data is None: - break - - new_proof = proof_of_work(data) + data = None + new_proof = None + while new_proof is None: + data = getLastblock() + if data is None: + break + new_proof = proof_of_work(data, 1000000) # When found, POST it to the server {"proof": new_proof, "id": id} post_data = {"proof": new_proof, "id": id} From 3913ae69d24edd3236749388b08b8f60e8d2a786 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 16:51:40 -0600 Subject: [PATCH 09/21] (feat) allows the server to adjust difficulty and communicates it to an endpoint client then checks difficulty before each grouping of attempts --- client_mining_p/blockchain.py | 10 +++++++--- client_mining_p/miner.py | 16 +++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/client_mining_p/blockchain.py b/client_mining_p/blockchain.py index 0e52480f..68892766 100644 --- a/client_mining_p/blockchain.py +++ b/client_mining_p/blockchain.py @@ -14,6 +14,8 @@ def __init__(self): # Create the genesis block self.new_block(previous_hash=-1, proof=0) + self.difficulty = 5 + def new_block(self, proof, previous_hash=None): """ Create a new Block in the Blockchain @@ -92,7 +94,7 @@ def valid_proof(block_string, proof): guess = f"{block_string}{proof}".encode() guessHash = hashlib.sha256(guess).hexdigest() - return guessHash[:6] == "000000" + return guessHash[:blockchain.difficulty] == "0" * blockchain.difficulty @staticmethod def valid_proof_block(block, proof): @@ -137,8 +139,6 @@ def mine(): "status": "failure", } return jsonify(response), 401 - - @app.route('/chain', methods=['GET']) def full_chain(): @@ -154,6 +154,10 @@ def full_chain(): def lastBlock(): return jsonify(blockchain.last_block), 200 +@app.route("/difficulty", methods=["GET"]) +def difficulty(): + return jsonify(blockchain.difficulty), 200 + # Run the program on port 5000 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) diff --git a/client_mining_p/miner.py b/client_mining_p/miner.py index 8816fa78..41a5c3d4 100644 --- a/client_mining_p/miner.py +++ b/client_mining_p/miner.py @@ -7,7 +7,7 @@ import random -def proof_of_work(block, iterations): +def proof_of_work(block, iterations, difficulty): """ Simple Proof of Work Algorithm Stringify the block and look for a proof. @@ -18,12 +18,12 @@ def proof_of_work(block, iterations): blockString = json.dumps(block, sort_keys=True) for i in range(iterations): proof = int(random.random() * 100000000) - if valid_proof(blockString, proof): + if valid_proof(blockString, proof, difficulty): return proof return None -def valid_proof(block_string, proof): +def valid_proof(block_string, proof, difficulty): """ Validates the Proof: Does hash(block_string, proof) contain 6 leading zeroes? Return true if the proof is valid @@ -36,21 +36,23 @@ def valid_proof(block_string, proof): """ guess = f"{block_string}{proof}".encode() guessHash = hashlib.sha256(guess).hexdigest() - return guessHash[:6] == "000000" + return guessHash[:difficulty] == "0" * difficulty def getLastblock(): r = requests.get(url=node + "/lastblock") + diff = requests.get(url=node + "/difficulty") # Handle non-json response try: data = r.json() + difficulty = diff.json() except ValueError: print("Error: Non-json response") print("Response returned:") print(r) return None - return data + return (data, difficulty) def submitProof(new_proof): # When found, POST it to the server {"proof": new_proof, "id": id} @@ -93,10 +95,10 @@ def submitProof(new_proof): data = None new_proof = None while new_proof is None: - data = getLastblock() + data, difficulty = getLastblock() if data is None: break - new_proof = proof_of_work(data, 1000000) + new_proof = proof_of_work(data, 1000000, difficulty) # When found, POST it to the server {"proof": new_proof, "id": id} post_data = {"proof": new_proof, "id": id} From e2cb7fd714a78e74da453e1f2a253a077851c752 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Wed, 12 Feb 2020 16:54:14 -0600 Subject: [PATCH 10/21] added paw file --- client_mining_p/endpoints.paw | Bin 0 -> 6856 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client_mining_p/endpoints.paw diff --git a/client_mining_p/endpoints.paw b/client_mining_p/endpoints.paw new file mode 100644 index 0000000000000000000000000000000000000000..250b283afe5fa50e3ee4dff4757a6ff9d7a00833 GIT binary patch literal 6856 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 literal 0 HcmV?d00001 From d430599f915845f7d7ce45a95b7f4338b5061870 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 15:02:21 -0600 Subject: [PATCH 11/21] updated gitignore --- .gitignore | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) diff --git a/.gitignore b/.gitignore index 32e51ca3..74d51f9f 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,200 @@ my_id.txt #vscode local settings .vscode/ + + +# Created by https://www.gitignore.io/api/linux,swift,xcode,macos,carthage,cocoapods,objective-c +# Edit at https://www.gitignore.io/?templates=linux,swift,xcode,macos,carthage,cocoapods,objective-c + +### Carthage ### +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +### CocoaPods ### +## CocoaPods GitIgnore Template + +# CocoaPods - Only use to conserve bandwidth / Save time on Pushing +# - Also handy if you have a large number of dependant pods +# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE +Pods/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Objective-C ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + + +# fastlane +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### Objective-C Patch ### + +### Swift ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + + + + + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +.build/ +# Add this line if you want to avoid checking in Xcode SPM integration. +# .swiftpm/xcode + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + + +### Xcode ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) + +## Xcode Patch +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno + +### Xcode Patch ### +**/xcshareddata/WorkspaceSettings.xcsettings + +# End of https://www.gitignore.io/api/linux,swift,xcode,macos,carthage,cocoapods,objective-c From f40d264810a8c9e7b31c353a3e25078741885876 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 15:03:16 -0600 Subject: [PATCH 12/21] (feat) added transaction support (guided project) --- basic_transactions_gp/blockchain.py | 213 +++++++++++++++++++++++++++- client_mining_p/endpoints.paw | Bin 6856 -> 7637 bytes 2 files changed, 211 insertions(+), 2 deletions(-) diff --git a/basic_transactions_gp/blockchain.py b/basic_transactions_gp/blockchain.py index 5a2c7e5a..8110a842 100644 --- a/basic_transactions_gp/blockchain.py +++ b/basic_transactions_gp/blockchain.py @@ -1,2 +1,211 @@ -# Paste your version of blockchain.py from the client_mining_p -# folder here +import hashlib +import json +from time import time +from uuid import uuid4 + +from flask import Flask, jsonify, request + + +class Blockchain(object): + def __init__(self): + self.chain = [] + self.current_transactions = [] + + # Create the genesis block + self.new_block(previous_hash=-1, proof=0) + + self.difficulty = 5 + + def new_block(self, proof, previous_hash=None): + """ + Create a new Block in the Blockchain + + A block should have: + * Index + * Timestamp + * List of current transactions + * The proof used to mine this block + * The hash of the previous block + + :param proof: The proof given by the Proof of Work algorithm + :param previous_hash: (Optional) Hash of previous Block + :return: New Block + """ + block = { + 'index': len(self.chain) + 1, + 'timestamp': time(), + 'transactions': self.current_transactions, + 'proof': proof, + 'previous_hash': previous_hash or self.hash(self.chain[-1]) + } + + # Reset the current list of transactions + self.current_transactions = [] + # Append the block to the chain + self.chain.append(block) + # Return the new block + return block + + def newTransaction(self, sender, recipient, amount): + """ + : param sender: < str > Address of the Recipient + : param recipient: < str > Address of the Recipient + : param amount: < int > Amount + : return: < int > The index of the `block` that will hold this transaction + """ + transaction = { + "sender": sender, + "recipient": recipient, + "amount": float(amount) + } + + self.current_transactions.append(transaction) + + return self.last_block['index'] + 1 + + def hash(self, block): + """ + Creates a SHA-256 hash of a Block + + :param block": Block + "return": + """ + stringObject = json.dumps(block, sort_keys=True) + blockString = stringObject.encode() + + rawHash = hashlib.sha256(blockString) + hexHash = rawHash.hexdigest() + return hexHash + + def balanceForUser(self, user): + balance = 0 + allXtions = [block["transactions"] for block in self.chain] + allXtions += self.current_transactions + for blockTransactions in allXtions: + for transaction in blockTransactions: + if transaction["sender"] == user: + balance -= transaction["amount"] + if transaction["recipient"] == user: + balance += transaction["amount"] + + return balance + + @property + def last_block(self): + return self.chain[-1] + + @staticmethod + def valid_proof(block_string, proof): + """ + Validates the Proof: Does hash(block_string, proof) contain 3 + leading zeroes? Return true if the proof is valid + :param block_string: The stringified block to use to + check in combination with `proof` + :param proof: The value that when combined with the + stringified previous block results in a hash that has the + correct number of leading zeroes. + :return: True if the resulting hash is a valid proof, False otherwise + """ + guess = f"{block_string}{proof}".encode() + guessHash = hashlib.sha256(guess).hexdigest() + + return guessHash[:blockchain.difficulty] == "0" * blockchain.difficulty + + @staticmethod + def valid_proof_block(block, proof): + properties = [block.get("index", None), block.get("timestamp", None), block.get( + "transactions", None), block.get("proof", None), block.get("previous_hash", None)] + if len([x for x in properties if x is not None]) != 5: + print("invalid block structure") + return False + blockString = json.dumps(block, sort_keys=True) + return Blockchain.valid_proof(blockString, proof) + + +# Instantiate our Node +app = Flask(__name__) + +# Generate a globally unique address for this node +node_identifier = str(uuid4()).replace('-', '') + +# Instantiate the Blockchain +blockchain = Blockchain() + + +@app.route('/mine', methods=['POST']) +def mine(): + jsonStr = request.data.decode("utf-8") + incomingMinedBlock = json.loads(jsonStr) + newProof = incomingMinedBlock.get("proof", None) + clientID = incomingMinedBlock.get("id", None) + if newProof is None or clientID is None: + return jsonify({"error": "Invalid proof info"}), 400 + newProof = int(newProof) + + if Blockchain.valid_proof_block(blockchain.last_block, newProof): + # successful = add new block and return message indicating success + previousHash = blockchain.hash(blockchain.last_block) + + blockIndex = blockchain.newTransaction(0, clientID, 1) + + newBlock = blockchain.new_block(newProof, previousHash) + response = { + "status": "success", + "block": newBlock, + "reward": f"reward paid in block {blockIndex}" + } + return jsonify(response), 200 + else: + response = { + "status": "failure", + } + return jsonify(response), 200 + + +@app.route('/chain', methods=['GET']) +def full_chain(): + response = { + # Return the chain and its current length + 'chain': blockchain.chain, + 'length': len(blockchain.chain), + } + return jsonify(response), 200 + +@app.route("/transaction/new", methods=['POST']) +def receiveNewTransaction(): + jsonStr = request.data.decode("utf-8") + data = json.loads(jsonStr) + # data = request.get_json() + + required = ['sender', 'recipient', 'amount'] + if not all(k in data for k in required): + return jsonify({"error": "Missing Values"}), 400 + sender = data['sender'] + recipient = data['recipient'] + amount = float(data['amount']) + + if blockchain.balanceForUser(sender) < amount: + response = { + "message": f"Insuffienct balance" + } + return jsonify(response), 200 + + index = blockchain.newTransaction(sender, recipient, amount) + response = { + "message": f"Transactions will be included in block {index}" + } + return jsonify(response), 200 + +@app.route('/lastblock', methods=['GET']) +def lastBlock(): + return jsonify(blockchain.last_block), 200 + + +@app.route("/difficulty", methods=["GET"]) +def difficulty(): + return jsonify(blockchain.difficulty), 200 + + +# Run the program on port 5000 +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) diff --git a/client_mining_p/endpoints.paw b/client_mining_p/endpoints.paw index 250b283afe5fa50e3ee4dff4757a6ff9d7a00833..b5bd4cebd796d9cd0b47adf5fb077f8e9a469df5 100644 GIT binary patch delta 3522 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 A7XSbN From ad50cb51f6b7f6ec6689f572ae3e1f3b42f2344b Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 16:13:16 -0600 Subject: [PATCH 13/21] (feat) swift ui configured for wallet --- .../BCWallet.xcodeproj/project.pbxproj | 347 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../BCWallet/BCWallet/AppDelegate.swift | 37 ++ .../AppIcon.appiconset/Contents.json | 98 +++++ .../BCWallet/Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../BCWallet/BCWallet/ContentView.swift | 73 ++++ basic_wallet_p/BCWallet/BCWallet/Info.plist | 60 +++ .../Preview Assets.xcassets/Contents.json | 6 + .../BCWallet/BCWallet/SceneDelegate.swift | 64 ++++ 11 files changed, 731 insertions(+) create mode 100644 basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj create mode 100644 basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 basic_wallet_p/BCWallet/BCWallet/AppDelegate.swift create mode 100644 basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/Contents.json create mode 100644 basic_wallet_p/BCWallet/BCWallet/Base.lproj/LaunchScreen.storyboard create mode 100644 basic_wallet_p/BCWallet/BCWallet/ContentView.swift create mode 100644 basic_wallet_p/BCWallet/BCWallet/Info.plist create mode 100644 basic_wallet_p/BCWallet/BCWallet/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 basic_wallet_p/BCWallet/BCWallet/SceneDelegate.swift diff --git a/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1d3c54dd --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj @@ -0,0 +1,347 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 33C45B5623F5F12A00D73231 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33C45B5523F5F12A00D73231 /* AppDelegate.swift */; }; + 33C45B5823F5F12A00D73231 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33C45B5723F5F12A00D73231 /* SceneDelegate.swift */; }; + 33C45B5A23F5F12A00D73231 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33C45B5923F5F12A00D73231 /* ContentView.swift */; }; + 33C45B5C23F5F12E00D73231 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B5B23F5F12E00D73231 /* Assets.xcassets */; }; + 33C45B5F23F5F12E00D73231 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B5E23F5F12E00D73231 /* Preview Assets.xcassets */; }; + 33C45B6223F5F12E00D73231 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B6023F5F12E00D73231 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 33C45B5223F5F12A00D73231 /* BCWallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BCWallet.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33C45B5523F5F12A00D73231 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33C45B5723F5F12A00D73231 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 33C45B5923F5F12A00D73231 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 33C45B5B23F5F12E00D73231 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 33C45B5E23F5F12E00D73231 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 33C45B6123F5F12E00D73231 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 33C45B6323F5F12E00D73231 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33C45B4F23F5F12A00D73231 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33C45B4923F5F12A00D73231 = { + isa = PBXGroup; + children = ( + 33C45B5423F5F12A00D73231 /* BCWallet */, + 33C45B5323F5F12A00D73231 /* Products */, + ); + sourceTree = ""; + }; + 33C45B5323F5F12A00D73231 /* Products */ = { + isa = PBXGroup; + children = ( + 33C45B5223F5F12A00D73231 /* BCWallet.app */, + ); + name = Products; + sourceTree = ""; + }; + 33C45B5423F5F12A00D73231 /* BCWallet */ = { + isa = PBXGroup; + children = ( + 33C45B5523F5F12A00D73231 /* AppDelegate.swift */, + 33C45B5723F5F12A00D73231 /* SceneDelegate.swift */, + 33C45B5923F5F12A00D73231 /* ContentView.swift */, + 33C45B5B23F5F12E00D73231 /* Assets.xcassets */, + 33C45B6023F5F12E00D73231 /* LaunchScreen.storyboard */, + 33C45B6323F5F12E00D73231 /* Info.plist */, + 33C45B5D23F5F12E00D73231 /* Preview Content */, + ); + path = BCWallet; + sourceTree = ""; + }; + 33C45B5D23F5F12E00D73231 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 33C45B5E23F5F12E00D73231 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33C45B5123F5F12A00D73231 /* BCWallet */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33C45B6623F5F12E00D73231 /* Build configuration list for PBXNativeTarget "BCWallet" */; + buildPhases = ( + 33C45B4E23F5F12A00D73231 /* Sources */, + 33C45B4F23F5F12A00D73231 /* Frameworks */, + 33C45B5023F5F12A00D73231 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = BCWallet; + productName = BCWallet; + productReference = 33C45B5223F5F12A00D73231 /* BCWallet.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33C45B4A23F5F12A00D73231 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1130; + LastUpgradeCheck = 1130; + ORGANIZATIONNAME = "Red_Egg Productions"; + TargetAttributes = { + 33C45B5123F5F12A00D73231 = { + CreatedOnToolsVersion = 11.3.1; + }; + }; + }; + buildConfigurationList = 33C45B4D23F5F12A00D73231 /* Build configuration list for PBXProject "BCWallet" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33C45B4923F5F12A00D73231; + productRefGroup = 33C45B5323F5F12A00D73231 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33C45B5123F5F12A00D73231 /* BCWallet */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33C45B5023F5F12A00D73231 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33C45B6223F5F12E00D73231 /* LaunchScreen.storyboard in Resources */, + 33C45B5F23F5F12E00D73231 /* Preview Assets.xcassets in Resources */, + 33C45B5C23F5F12E00D73231 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33C45B4E23F5F12A00D73231 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33C45B5623F5F12A00D73231 /* AppDelegate.swift in Sources */, + 33C45B5823F5F12A00D73231 /* SceneDelegate.swift in Sources */, + 33C45B5A23F5F12A00D73231 /* ContentView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 33C45B6023F5F12E00D73231 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 33C45B6123F5F12E00D73231 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 33C45B6423F5F12E00D73231 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33C45B6523F5F12E00D73231 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 33C45B6723F5F12E00D73231 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"BCWallet/Preview Content\""; + DEVELOPMENT_TEAM = VXUQXR6S56; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = BCWallet/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.redeggproductions.BCWallet; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 33C45B6823F5F12E00D73231 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"BCWallet/Preview Content\""; + DEVELOPMENT_TEAM = VXUQXR6S56; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = BCWallet/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.redeggproductions.BCWallet; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33C45B4D23F5F12A00D73231 /* Build configuration list for PBXProject "BCWallet" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33C45B6423F5F12E00D73231 /* Debug */, + 33C45B6523F5F12E00D73231 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33C45B6623F5F12E00D73231 /* Build configuration list for PBXNativeTarget "BCWallet" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33C45B6723F5F12E00D73231 /* Debug */, + 33C45B6823F5F12E00D73231 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33C45B4A23F5F12A00D73231 /* Project object */; +} diff --git a/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..0ad83744 --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/basic_wallet_p/BCWallet/BCWallet/AppDelegate.swift b/basic_wallet_p/BCWallet/BCWallet/AppDelegate.swift new file mode 100644 index 00000000..f318a2b2 --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/AppDelegate.swift @@ -0,0 +1,37 @@ +// +// AppDelegate.swift +// BCWallet +// +// Created by Michael Redig on 2/13/20. +// Copyright © 2020 Red_Egg Productions. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/AppIcon.appiconset/Contents.json b/basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d8db8d65 --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/Contents.json b/basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/basic_wallet_p/BCWallet/BCWallet/Base.lproj/LaunchScreen.storyboard b/basic_wallet_p/BCWallet/BCWallet/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..865e9329 --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift new file mode 100644 index 00000000..73dda8bb --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift @@ -0,0 +1,73 @@ +// +// ContentView.swift +// BCWallet +// +// Created by Michael Redig on 2/13/20. +// Copyright © 2020 Red_Egg Productions. All rights reserved. +// + +import SwiftUI + +struct ContentView: View { + + @State private var data = ["a", "b", "c"] + + @State private var userID = "" + @State private var totalSent: CGFloat = 0 + @State private var totalReceived: CGFloat = 0 + @State private var currentBalance: CGFloat = 0 + + var body: some View { + Form { + Section(header: Text("Sign In:")) { + HStack(alignment: .center) { + Text("Enter your ID: ") + TextField("mahname", text: $userID) + .textFieldStyle(RoundedBorderTextFieldStyle()) + Button(action: { + switch Int.random(in: 0...4) { + case 0: + self.currentBalance += 10 + case 1: + self.currentBalance -= 10.5 + case 2: + self.totalReceived += 5 + case 3: + self.totalSent += 6.4 + case 4: + let alpha = Array("abcdefghijklmnopqrstuvwxyz").compactMap { String($0) } + self.data.append(alpha.randomElement() ?? "wrong") + default: + print("defaulted?") + } + }) { + Text("Submit") + } + } + .frame(maxWidth: .infinity) + } + + Section(header: Text("Current Balance")) { + Text("\(currentBalance) coins") + } + Section(header: Text("Total Sent")) { + Text("\(totalSent) coins") + } + Section(header: Text("Total Received")) { + Text("\(totalReceived) coins") + } + + Section(header: Text("Data")) { + List(data, id: \.self) { datum in + Text(datum) + } + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/basic_wallet_p/BCWallet/BCWallet/Info.plist b/basic_wallet_p/BCWallet/BCWallet/Info.plist new file mode 100644 index 00000000..9742bf0f --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/Info.plist @@ -0,0 +1,60 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/basic_wallet_p/BCWallet/BCWallet/Preview Content/Preview Assets.xcassets/Contents.json b/basic_wallet_p/BCWallet/BCWallet/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/basic_wallet_p/BCWallet/BCWallet/SceneDelegate.swift b/basic_wallet_p/BCWallet/BCWallet/SceneDelegate.swift new file mode 100644 index 00000000..e35d5e89 --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/SceneDelegate.swift @@ -0,0 +1,64 @@ +// +// SceneDelegate.swift +// BCWallet +// +// Created by Michael Redig on 2/13/20. +// Copyright © 2020 Red_Egg Productions. All rights reserved. +// + +import UIKit +import SwiftUI + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + + // Create the SwiftUI view that provides the window contents. + let contentView = ContentView() + + // Use a UIHostingController as window root view controller. + if let windowScene = scene as? UIWindowScene { + let window = UIWindow(windowScene: windowScene) + window.rootViewController = UIHostingController(rootView: contentView) + self.window = window + window.makeKeyAndVisible() + } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + From 525cc6645104dbbdd9dc631cb84c713eb48253b8 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 16:49:59 -0600 Subject: [PATCH 14/21] (fix) tweaked server to provide consistent json --- basic_transactions_gp/blockchain.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/basic_transactions_gp/blockchain.py b/basic_transactions_gp/blockchain.py index 8110a842..9044f002 100644 --- a/basic_transactions_gp/blockchain.py +++ b/basic_transactions_gp/blockchain.py @@ -12,7 +12,7 @@ def __init__(self): self.current_transactions = [] # Create the genesis block - self.new_block(previous_hash=-1, proof=0) + self.new_block(previous_hash="-1", proof=0) self.difficulty = 5 @@ -36,7 +36,7 @@ def new_block(self, proof, previous_hash=None): 'timestamp': time(), 'transactions': self.current_transactions, 'proof': proof, - 'previous_hash': previous_hash or self.hash(self.chain[-1]) + 'previousHash': previous_hash or self.hash(self.chain[-1]) } # Reset the current list of transactions @@ -114,7 +114,7 @@ def valid_proof(block_string, proof): @staticmethod def valid_proof_block(block, proof): properties = [block.get("index", None), block.get("timestamp", None), block.get( - "transactions", None), block.get("proof", None), block.get("previous_hash", None)] + "transactions", None), block.get("proof", None), block.get("previousHash", None)] if len([x for x in properties if x is not None]) != 5: print("invalid block structure") return False @@ -146,7 +146,7 @@ def mine(): # successful = add new block and return message indicating success previousHash = blockchain.hash(blockchain.last_block) - blockIndex = blockchain.newTransaction(0, clientID, 1) + blockIndex = blockchain.newTransaction("0", clientID, 1) newBlock = blockchain.new_block(newProof, previousHash) response = { From 5a77970e244ea3adc22acbb8cc9b5edae6f0ecde Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 16:51:15 -0600 Subject: [PATCH 15/21] (feat) fetch chain from server added network handler to fetch --- .gitignore | 3 +- .../BCWallet.xcodeproj/project.pbxproj | 62 ++++++++++++++++++- .../BCWallet/BCWallet/ChainController.swift | 54 ++++++++++++++++ .../BCWallet/BCWallet/ContentView.swift | 27 +++----- basic_wallet_p/BCWallet/BCWallet/Info.plist | 5 ++ basic_wallet_p/BCWallet/Cartfile | 1 + basic_wallet_p/BCWallet/Cartfile.resolved | 1 + basic_wallet_p/BCWallet/input.xcfilelist | 1 + basic_wallet_p/BCWallet/output.xcfilelist | 1 + 9 files changed, 136 insertions(+), 19 deletions(-) create mode 100644 basic_wallet_p/BCWallet/BCWallet/ChainController.swift create mode 100644 basic_wallet_p/BCWallet/Cartfile create mode 100644 basic_wallet_p/BCWallet/Cartfile.resolved create mode 100644 basic_wallet_p/BCWallet/input.xcfilelist create mode 100644 basic_wallet_p/BCWallet/output.xcfilelist diff --git a/.gitignore b/.gitignore index 74d51f9f..d304d727 100644 --- a/.gitignore +++ b/.gitignore @@ -119,7 +119,7 @@ my_id.txt # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts -Carthage/Build +Carthage ### CocoaPods ### ## CocoaPods GitIgnore Template @@ -305,3 +305,4 @@ Dependencies/ **/xcshareddata/WorkspaceSettings.xcsettings # End of https://www.gitignore.io/api/linux,swift,xcode,macos,carthage,cocoapods,objective-c + diff --git a/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj index 1d3c54dd..88741ee1 100644 --- a/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj +++ b/basic_wallet_p/BCWallet/BCWallet.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -13,6 +13,11 @@ 33C45B5C23F5F12E00D73231 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B5B23F5F12E00D73231 /* Assets.xcassets */; }; 33C45B5F23F5F12E00D73231 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B5E23F5F12E00D73231 /* Preview Assets.xcassets */; }; 33C45B6223F5F12E00D73231 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B6023F5F12E00D73231 /* LaunchScreen.storyboard */; }; + 33C45B6A23F602A700D73231 /* Cartfile in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B6923F602A700D73231 /* Cartfile */; }; + 33C45B6D23F6031100D73231 /* input.xcfilelist in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B6B23F6031100D73231 /* input.xcfilelist */; }; + 33C45B6E23F6031100D73231 /* output.xcfilelist in Resources */ = {isa = PBXBuildFile; fileRef = 33C45B6C23F6031100D73231 /* output.xcfilelist */; }; + 33C45B7123F6032F00D73231 /* NetworkHandler.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33C45B7023F6032F00D73231 /* NetworkHandler.framework */; }; + 33C45B7423F603B900D73231 /* ChainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33C45B7323F603B900D73231 /* ChainController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,6 +29,11 @@ 33C45B5E23F5F12E00D73231 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 33C45B6123F5F12E00D73231 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 33C45B6323F5F12E00D73231 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 33C45B6923F602A700D73231 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; }; + 33C45B6B23F6031100D73231 /* input.xcfilelist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcfilelist; path = input.xcfilelist; sourceTree = ""; }; + 33C45B6C23F6031100D73231 /* output.xcfilelist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcfilelist; path = output.xcfilelist; sourceTree = ""; }; + 33C45B7023F6032F00D73231 /* NetworkHandler.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkHandler.framework; path = Carthage/Build/iOS/NetworkHandler.framework; sourceTree = ""; }; + 33C45B7323F603B900D73231 /* ChainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -31,6 +41,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 33C45B7123F6032F00D73231 /* NetworkHandler.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -40,8 +51,12 @@ 33C45B4923F5F12A00D73231 = { isa = PBXGroup; children = ( + 33C45B6923F602A700D73231 /* Cartfile */, + 33C45B6B23F6031100D73231 /* input.xcfilelist */, + 33C45B6C23F6031100D73231 /* output.xcfilelist */, 33C45B5423F5F12A00D73231 /* BCWallet */, 33C45B5323F5F12A00D73231 /* Products */, + 33C45B6F23F6032300D73231 /* Frameworks */, ); sourceTree = ""; }; @@ -59,6 +74,7 @@ 33C45B5523F5F12A00D73231 /* AppDelegate.swift */, 33C45B5723F5F12A00D73231 /* SceneDelegate.swift */, 33C45B5923F5F12A00D73231 /* ContentView.swift */, + 33C45B7323F603B900D73231 /* ChainController.swift */, 33C45B5B23F5F12E00D73231 /* Assets.xcassets */, 33C45B6023F5F12E00D73231 /* LaunchScreen.storyboard */, 33C45B6323F5F12E00D73231 /* Info.plist */, @@ -75,6 +91,14 @@ path = "Preview Content"; sourceTree = ""; }; + 33C45B6F23F6032300D73231 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 33C45B7023F6032F00D73231 /* NetworkHandler.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -85,6 +109,7 @@ 33C45B4E23F5F12A00D73231 /* Sources */, 33C45B4F23F5F12A00D73231 /* Frameworks */, 33C45B5023F5F12A00D73231 /* Resources */, + 33C45B7223F6033C00D73231 /* Run Script - Carthage */, ); buildRules = ( ); @@ -134,13 +159,39 @@ buildActionMask = 2147483647; files = ( 33C45B6223F5F12E00D73231 /* LaunchScreen.storyboard in Resources */, + 33C45B6D23F6031100D73231 /* input.xcfilelist in Resources */, 33C45B5F23F5F12E00D73231 /* Preview Assets.xcassets in Resources */, + 33C45B6E23F6031100D73231 /* output.xcfilelist in Resources */, + 33C45B6A23F602A700D73231 /* Cartfile in Resources */, 33C45B5C23F5F12E00D73231 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 33C45B7223F6033C00D73231 /* Run Script - Carthage */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "$(SRCROOT)/input.xcfilelist", + ); + inputPaths = ( + ); + name = "Run Script - Carthage"; + outputFileListPaths = ( + "$(SRCROOT)/output.xcfilelist", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks\n/usr/local/bin/carthage outdated --xcode-warnings\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 33C45B4E23F5F12A00D73231 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -149,6 +200,7 @@ 33C45B5623F5F12A00D73231 /* AppDelegate.swift in Sources */, 33C45B5823F5F12A00D73231 /* SceneDelegate.swift in Sources */, 33C45B5A23F5F12A00D73231 /* ContentView.swift in Sources */, + 33C45B7423F603B900D73231 /* ChainController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -288,6 +340,10 @@ DEVELOPMENT_ASSET_PATHS = "\"BCWallet/Preview Content\""; DEVELOPMENT_TEAM = VXUQXR6S56; ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = BCWallet/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -308,6 +364,10 @@ DEVELOPMENT_ASSET_PATHS = "\"BCWallet/Preview Content\""; DEVELOPMENT_TEAM = VXUQXR6S56; ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = BCWallet/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/basic_wallet_p/BCWallet/BCWallet/ChainController.swift b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift new file mode 100644 index 00000000..232f9420 --- /dev/null +++ b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift @@ -0,0 +1,54 @@ +// +// ChainController.swift +// BCWallet +// +// Created by Michael Redig on 2/13/20. +// Copyright © 2020 Red_Egg Productions. All rights reserved. +// + +import Foundation +import NetworkHandler + +class ChainController { + + var chain: [Block] = [] + let handler = NetworkHandler() + + func getLatestChain(completion: @escaping (ChainController) -> Void) { + let url = URL(string: "http://localhost:5000/chain")! + + handler.transferMahCodableDatas(with: url.request) { (result: Result) -> Void in + switch result { + case .success(let chain): + self.chain = chain.chain + case .failure(let error): + print("error fetching chain: \(error)") + } + completion(self) + } + } + + func balance(for user: String) -> (balance: Double, sent: Double, received: Double) { + + return (0,0,0) + } +} + +struct Chain: Codable { + let chain: [Block] + let length: Int +} + +struct Block: Codable { + let index: Int + let previousHash: String + let proof: Int + let timestamp: Double + let transactions: [Transaction] +} + +struct Transaction: Codable { + let sender: String + let recipient: String + let amount: Double +} diff --git a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift index 73dda8bb..d79f730e 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift @@ -7,9 +7,12 @@ // import SwiftUI +import NetworkHandler struct ContentView: View { + private let controller = ChainController() + @State private var data = ["a", "b", "c"] @State private var userID = "" @@ -24,23 +27,7 @@ struct ContentView: View { Text("Enter your ID: ") TextField("mahname", text: $userID) .textFieldStyle(RoundedBorderTextFieldStyle()) - Button(action: { - switch Int.random(in: 0...4) { - case 0: - self.currentBalance += 10 - case 1: - self.currentBalance -= 10.5 - case 2: - self.totalReceived += 5 - case 3: - self.totalSent += 6.4 - case 4: - let alpha = Array("abcdefghijklmnopqrstuvwxyz").compactMap { String($0) } - self.data.append(alpha.randomElement() ?? "wrong") - default: - print("defaulted?") - } - }) { + Button(action: fetchBalance) { Text("Submit") } } @@ -64,6 +51,12 @@ struct ContentView: View { } } } + + func fetchBalance() { + controller.getLatestChain { controller in + print(controller.chain) + } + } } struct ContentView_Previews: PreviewProvider { diff --git a/basic_wallet_p/BCWallet/BCWallet/Info.plist b/basic_wallet_p/BCWallet/BCWallet/Info.plist index 9742bf0f..cf16f92d 100644 --- a/basic_wallet_p/BCWallet/BCWallet/Info.plist +++ b/basic_wallet_p/BCWallet/BCWallet/Info.plist @@ -20,6 +20,11 @@ 1 LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/basic_wallet_p/BCWallet/Cartfile b/basic_wallet_p/BCWallet/Cartfile new file mode 100644 index 00000000..cd2654c1 --- /dev/null +++ b/basic_wallet_p/BCWallet/Cartfile @@ -0,0 +1 @@ +github "mredig/NetworkHandler" diff --git a/basic_wallet_p/BCWallet/Cartfile.resolved b/basic_wallet_p/BCWallet/Cartfile.resolved new file mode 100644 index 00000000..54b7f928 --- /dev/null +++ b/basic_wallet_p/BCWallet/Cartfile.resolved @@ -0,0 +1 @@ +github "mredig/NetworkHandler" "0.9.4" diff --git a/basic_wallet_p/BCWallet/input.xcfilelist b/basic_wallet_p/BCWallet/input.xcfilelist new file mode 100644 index 00000000..251bcc6b --- /dev/null +++ b/basic_wallet_p/BCWallet/input.xcfilelist @@ -0,0 +1 @@ +$(SRCROOT)/Carthage/Build/iOS/NetworkHandler.framework diff --git a/basic_wallet_p/BCWallet/output.xcfilelist b/basic_wallet_p/BCWallet/output.xcfilelist new file mode 100644 index 00000000..67744566 --- /dev/null +++ b/basic_wallet_p/BCWallet/output.xcfilelist @@ -0,0 +1 @@ +$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/NetworkHandler.framework From bd3cf300553a27d0c528b072cbe57f8014a79b48 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 17:14:08 -0600 Subject: [PATCH 16/21] (feat) ui displays user's balance --- .../BCWallet/BCWallet/ChainController.swift | 18 +++++++++++++++++- .../BCWallet/BCWallet/ContentView.swift | 11 +++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/basic_wallet_p/BCWallet/BCWallet/ChainController.swift b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift index 232f9420..8528f825 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ChainController.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift @@ -29,8 +29,24 @@ class ChainController { } func balance(for user: String) -> (balance: Double, sent: Double, received: Double) { + var balance = 0.0 + var totalSent = 0.0 + var totalReceived = 0.0 - return (0,0,0) + let xtions = chain.flatMap { $0.transactions }.filter { $0.sender == user || $0.recipient == user } + + for transaction in xtions { + if transaction.sender == user { + balance -= transaction.amount + totalSent += transaction.amount + } + if transaction.recipient == user { + balance += transaction.amount + totalReceived += transaction.amount + } + } + + return (balance, totalSent, totalReceived) } } diff --git a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift index d79f730e..088576ab 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift @@ -16,9 +16,9 @@ struct ContentView: View { @State private var data = ["a", "b", "c"] @State private var userID = "" - @State private var totalSent: CGFloat = 0 - @State private var totalReceived: CGFloat = 0 - @State private var currentBalance: CGFloat = 0 + @State private var totalSent = 0.0 + @State private var totalReceived = 0.0 + @State private var currentBalance = 0.0 var body: some View { Form { @@ -54,7 +54,10 @@ struct ContentView: View { func fetchBalance() { controller.getLatestChain { controller in - print(controller.chain) + let balanceInfo = controller.balance(for: self.userID) + self.currentBalance = balanceInfo.balance + self.totalSent = balanceInfo.sent + self.totalReceived = balanceInfo.received } } } From 51038112d853994e0c2c673dd1e90f366bbffb43 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 17:22:59 -0600 Subject: [PATCH 17/21] (feat) added timestamp and id to transactions --- basic_transactions_gp/blockchain.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/basic_transactions_gp/blockchain.py b/basic_transactions_gp/blockchain.py index 9044f002..782fe2df 100644 --- a/basic_transactions_gp/blockchain.py +++ b/basic_transactions_gp/blockchain.py @@ -56,7 +56,9 @@ def newTransaction(self, sender, recipient, amount): transaction = { "sender": sender, "recipient": recipient, - "amount": float(amount) + "amount": float(amount), + "timestamp": time(), + "id": str(uuid4()) } self.current_transactions.append(transaction) From 99acdaa2e8535a0ee8053db8bf853d8437995d14 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 17:23:13 -0600 Subject: [PATCH 18/21] show transaction history in wallet ui --- .../BCWallet/BCWallet/ChainController.swift | 18 +++++++++++++----- .../BCWallet/BCWallet/ContentView.swift | 9 ++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/basic_wallet_p/BCWallet/BCWallet/ChainController.swift b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift index 8528f825..f0704f68 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ChainController.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift @@ -28,14 +28,16 @@ class ChainController { } } - func balance(for user: String) -> (balance: Double, sent: Double, received: Double) { + func transactions(for user: String) -> [Transaction] { + chain.flatMap { $0.transactions }.filter { $0.sender == user || $0.recipient == user } + } + + func balance(for user: String, transactions: [Transaction]) -> (balance: Double, sent: Double, received: Double) { var balance = 0.0 var totalSent = 0.0 var totalReceived = 0.0 - let xtions = chain.flatMap { $0.transactions }.filter { $0.sender == user || $0.recipient == user } - - for transaction in xtions { + for transaction in transactions { if transaction.sender == user { balance -= transaction.amount totalSent += transaction.amount @@ -63,8 +65,14 @@ struct Block: Codable { let transactions: [Transaction] } -struct Transaction: Codable { +struct Transaction: Codable, Hashable, CustomStringConvertible { let sender: String let recipient: String let amount: Double + let timestamp: Double + let id: String + + var description: String { + "\(sender) sent \(amount) coins to \(recipient) at \(timestamp)" + } } diff --git a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift index 088576ab..6551e280 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift @@ -13,7 +13,7 @@ struct ContentView: View { private let controller = ChainController() - @State private var data = ["a", "b", "c"] + @State private var data = [Transaction]() @State private var userID = "" @State private var totalSent = 0.0 @@ -46,7 +46,7 @@ struct ContentView: View { Section(header: Text("Data")) { List(data, id: \.self) { datum in - Text(datum) + Text("\(datum.description)") } } } @@ -54,7 +54,10 @@ struct ContentView: View { func fetchBalance() { controller.getLatestChain { controller in - let balanceInfo = controller.balance(for: self.userID) + let transactions = controller.transactions(for: self.userID) + self.data = transactions + + let balanceInfo = controller.balance(for: self.userID, transactions: transactions) self.currentBalance = balanceInfo.balance self.totalSent = balanceInfo.sent self.totalReceived = balanceInfo.received From 94bae62959c2625ec22aa86ad617c82d0f0c3f20 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 18:22:07 -0600 Subject: [PATCH 19/21] (feat) ui can send money --- .../BCWallet/BCWallet/ChainController.swift | 40 ++++++++++++++++++- .../BCWallet/BCWallet/ContentView.swift | 39 +++++++++++++++++- client_mining_p/miner.py | 16 +++++--- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/basic_wallet_p/BCWallet/BCWallet/ChainController.swift b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift index f0704f68..e92ca7e3 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ChainController.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ChainController.swift @@ -14,8 +14,10 @@ class ChainController { var chain: [Block] = [] let handler = NetworkHandler() + private let baseURL = URL(string: "http://localhost:5000")! + func getLatestChain(completion: @escaping (ChainController) -> Void) { - let url = URL(string: "http://localhost:5000/chain")! + let url = baseURL.appendingPathComponent("chain") handler.transferMahCodableDatas(with: url.request) { (result: Result) -> Void in switch result { @@ -28,6 +30,38 @@ class ChainController { } } + func sendMoney(from sender: String, to recipient: String, amount: Double, completion: @escaping (ChainController, NetworkError?) -> Void) { + let url = baseURL + .appendingPathComponent("transaction") + .appendingPathComponent("new") + + let trans = Transaction(sender: sender, recipient: recipient, amount: amount, timestamp: Date().timeIntervalSince1970, id: "") + + let json = try! JSONEncoder().encode(trans) + + var request = url.request + request.httpMethod = .post + request.httpBody = json + request.addValue(.contentType(type: .json), forHTTPHeaderField: .commonKey(key: .contentType)) + + handler.transferMahCodableDatas(with: request) { (result: Result) -> Void in + switch result { + case .success: + completion(self, nil) + case .failure(let error): + completion(self, error) + switch error { + case .httpNon200StatusCode(code: let code, data: let data): + print(code) + let str = String(data: data!, encoding: .utf8)! + print(str) + default: + break + } + } + } + } + func transactions(for user: String) -> [Transaction] { chain.flatMap { $0.transactions }.filter { $0.sender == user || $0.recipient == user } } @@ -76,3 +110,7 @@ struct Transaction: Codable, Hashable, CustomStringConvertible { "\(sender) sent \(amount) coins to \(recipient) at \(timestamp)" } } + +struct Message: Codable { + let message: String +} diff --git a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift index 6551e280..a89181a6 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift @@ -20,13 +20,18 @@ struct ContentView: View { @State private var totalReceived = 0.0 @State private var currentBalance = 0.0 - var body: some View { + @State private var sendAmount = "" + @State private var recipient = "" + + var body: some View { Form { Section(header: Text("Sign In:")) { HStack(alignment: .center) { Text("Enter your ID: ") TextField("mahname", text: $userID) .textFieldStyle(RoundedBorderTextFieldStyle()) + .textContentType(.username) + .autocapitalization(.none) Button(action: fetchBalance) { Text("Submit") } @@ -34,6 +39,24 @@ struct ContentView: View { .frame(maxWidth: .infinity) } + Section(header: Text("Send Money")) { + HStack { + TextField("0", text: $sendAmount) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .keyboardType(.decimalPad) + .textContentType(.oneTimeCode) + .autocapitalization(.none) + Text("to") + TextField("recipient", text: $recipient) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .textContentType(.username) + .autocapitalization(.none) + Button(action: sendMoney) { + Text("Send") + } + } + } + Section(header: Text("Current Balance")) { Text("\(currentBalance) coins") } @@ -63,6 +86,20 @@ struct ContentView: View { self.totalReceived = balanceInfo.received } } + + func sendMoney() { + guard let amount = Double(sendAmount) else { return } + + sendAmount = "" + recipient = "" + controller.sendMoney(from: userID, to: recipient, amount: amount) { controller, error in + if let error = error { + print("error: \(error)") + return + } + self.fetchBalance() + } + } } struct ContentView_Previews: PreviewProvider { diff --git a/client_mining_p/miner.py b/client_mining_p/miner.py index 41a5c3d4..435924b1 100644 --- a/client_mining_p/miner.py +++ b/client_mining_p/miner.py @@ -77,16 +77,20 @@ def submitProof(new_proof): if __name__ == '__main__': # What is the server address? IE `python3 miner.py https://server.com/api/` + # if len(sys.argv) > 1: + # node = sys.argv[1] + # else: + node = "http://localhost:5000" + + # Load ID if len(sys.argv) > 1: - node = sys.argv[1] + id = sys.argv[1] else: - node = "http://localhost:5000" + f = open("my_id.txt", "r") + id = f.read() + f.close() - # Load ID - f = open("my_id.txt", "r") - id = f.read() print("ID is", id) - f.close() coins = 0 From cd79fbc1d1ece597fa95cf37afd60c6462998607 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Thu, 13 Feb 2020 18:27:37 -0600 Subject: [PATCH 20/21] (fix) dont just send to "" in ui --- basic_transactions_gp/blockchain.py | 2 +- basic_wallet_p/BCWallet/BCWallet/ContentView.swift | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/basic_transactions_gp/blockchain.py b/basic_transactions_gp/blockchain.py index 782fe2df..66ba5747 100644 --- a/basic_transactions_gp/blockchain.py +++ b/basic_transactions_gp/blockchain.py @@ -14,7 +14,7 @@ def __init__(self): # Create the genesis block self.new_block(previous_hash="-1", proof=0) - self.difficulty = 5 + self.difficulty = 6 def new_block(self, proof, previous_hash=None): """ diff --git a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift index a89181a6..ec0b4e7c 100644 --- a/basic_wallet_p/BCWallet/BCWallet/ContentView.swift +++ b/basic_wallet_p/BCWallet/BCWallet/ContentView.swift @@ -90,8 +90,6 @@ struct ContentView: View { func sendMoney() { guard let amount = Double(sendAmount) else { return } - sendAmount = "" - recipient = "" controller.sendMoney(from: userID, to: recipient, amount: amount) { controller, error in if let error = error { print("error: \(error)") @@ -99,6 +97,9 @@ struct ContentView: View { } self.fetchBalance() } + + sendAmount = "" + recipient = "" } } From f051d376e42a408e9e6d9b72d608b5c3c0c51699 Mon Sep 17 00:00:00 2001 From: Michael Redig Date: Sat, 15 Feb 2020 16:21:39 -0600 Subject: [PATCH 21/21] paw update --- client_mining_p/endpoints.paw | Bin 7637 -> 10480 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/client_mining_p/endpoints.paw b/client_mining_p/endpoints.paw index b5bd4cebd796d9cd0b47adf5fb077f8e9a469df5..9319c8f355975aafe2b7eda713ad44c99bd58f06 100644 GIT binary patch delta 5583 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