159 lines
5.2 KiB
Python
159 lines
5.2 KiB
Python
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()
|