from flask import Flask import json mine = Flask(__name__) db = mariadb.connect(**config) @app.get('/') def mine(): # TODO: return a page to mine through the browser return 200 ### # Submit a block to the chain. # This method calls the Block().validate() method to validate the block schema. # This method performs additional validations against the rest of the chain. ### @app.post('/blocks') def blocks_post(): previousBlock = get_last_block() try: newBlock = Block(data=request.get_json()) newBlock.validate() previousBlock = db.get_last_block() if newBlock.previousHash != previousBlock.blockHash: raise Block.Invalid( f"Incorrect previous hash - should be {previousBlock.blockHash}." ) if newBlock.timestamp <= previousBlock.timestamp: raise Block.Invalid( "Timestamp is later than previous block." ) if newBlock.height != previousBlock.height + 1: raise Block.Invalid( f"Incorrect block height - should be {previousBlock.height + 1}." ) if newBlock.difficulty != DIFFICULTY_REQUIREMENT: raise Block.Invalid( f"Incorrect difficulty - should be {DIFFICULTY_REQUIREMENT}." ) if len(newBlock.transactions) == 0: raise Block.Invalid( "Block contains no transactions." ) for transaction in newBlock.transactions: pendingTransaction = db.get_transaction(transaction.transactionId) if not pendingTransaction: raise Transaction.Invalid( f"No matching pending transaction for {transaction.transactionId}." ) if not pendingTransaction.pending: raise Transaction.AlreadyFulfilled( f"Transaction {transaction.transactionId} has already been fulfilled." ) if transaction.timestamp != pendingTransaction.timestamp: raise Transaction.Invalid( f"Incorrect timestamp on {transaction.transactionId}." ) if transaction.cardId != pendingTransaction.cardId: raise Transaction.Invalid( f"Incorrect cardId on {transaction.transactionId}." ) if transaction.sender != pendingTransaction.sender: raise Transaction.Invalid( f"Incorrect sender on {transaction.transactionId}." ) if transaction.recipient != pendingTransaction.recipient: raise Transaction.Invalid( f"Incorrect recipient on {transaction.transactionId}." ) if transaction.signature != pendingTransaction.signature: raise Transaction.Invalid( f"Incorrect signature on {transaction.transactionId}." ) # TODO: write to database with open(f"{DATA_PATH}/{newBlock.blockId}.json", 'w') as f: f.write(str(newBlock)) # TODO: update peers return str(newBlock), 200 except: Transaction.Invalid as e: return e, e.statusCode except: Transaction.AlreadyFulfilled as e: return e, e.statusCode except: Card.Invalid as e: return e, e.statusCode except: Block.Invalid as e: return e, e.statusCode ### # Retrieve blocks and block data. # Returns a skeleton block to be mined by default. # Queries for a specific block when given parameters. ### @app.get('/blocks') def blocks_get(): blockHash = request.args.get('blockHash', None) height = request.args.get('height', None) # TODO: block queries return str( Block( previousHash = lastBlock.blockHash, height = lastBlock.height + 1, difficulty = DIFFICULTY_REQUIREMENT, transactions = [ Transaction(data=each) for each in get_pending_transactions() ] ) ) ### # Retrieve card data ### @app.get('/cards') def cards_get(): # TODO: query cards return 200 ### # Submit a transaction to be mined in a block. # This method performs a number of validations on the submitted transaction and returns # a status code result. ### @app.put('/transactions') def transactions_put(): try: newTransaction = Transaction(data=request.get_json()) newTransaction.validate() # TODO: validate transaction against blockchain # TODO: add transaction to database # TODO: update peers? return 200 except Transaction.Unauthorized as e: return e, e.statusCode except Transaction.Invalid as e: return e, e.statusCode ### # Retrieve a transaction. ### @app.get('/transactions') def transactions_get(): transactionId = request.args.get('transactionId', None) return get_transaction_by_id(transactionId) if transactionId else json.dumps( db.get_pending_transactions() ) @app.post('/peers') def peers_post(): # TODO: validate peer # TODO: add peers to database return 200 @app.get('/peers') def peers_get(): # TODO: query peers return 200 if __name__ == "__main__": app.run()