wikideck/wikideck/Mine/Mine.py
Eric Meehan 14def28b68 Initial commit
Created basic application design and data schemas.
2025-05-28 19:24:37 -04:00

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()