commit d8e86367051846ac53af0a204e7ca1ba0ed4431c Author: f.strw Date: Thu Jun 6 23:00:13 2024 +0300 v. 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34eccc9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv/ +blockchain.json \ No newline at end of file diff --git a/blockchain.py b/blockchain.py new file mode 100644 index 0000000..5c5d0f8 --- /dev/null +++ b/blockchain.py @@ -0,0 +1,158 @@ +import hashlib +import json +import base64 +import os +import requests +from datetime import datetime +from flask import Flask, jsonify, request, render_template, flash, redirect, url_for + +class Block: + def __init__(self, index, timestamp, data, previous_hash): + self.index = index + self.timestamp = timestamp + self.data = data + self.previous_hash = previous_hash + self.hash = self.calculate_hash() + + def calculate_hash(self): + data_string = json.dumps(self.data, sort_keys=True) + return hashlib.sha256((str(self.index) + self.timestamp + data_string + self.previous_hash).encode()).hexdigest() + +class Blockchain: + def __init__(self): + self.chain = [] + self.load_chain() + + def create_genesis_block(self): + return Block(0, "00-00-0000", "Genesis Block", "0") + + def get_latest_block(self): + return self.chain[-1] + + def add_block(self, new_block): + new_block.previous_hash = self.get_latest_block().hash + new_block.hash = new_block.calculate_hash() + self.chain.append(new_block) + self.save_chain() + + def load_chain(self): + if os.path.exists('blockchain.json'): + with open('blockchain.json', 'r') as file: + chain_data = json.load(file) + for block_data in chain_data: + block = Block(block_data['index'], block_data['timestamp'], block_data['data'], block_data['previous_hash']) + block.hash = block_data['hash'] + self.chain.append(block) + else: + self.chain.append(self.create_genesis_block()) + + def save_chain(self): + chain_data = [] + for block in self.chain: + chain_data.append({ + 'index': block.index, + 'timestamp': block.timestamp, + 'data': block.data, + 'previous_hash': block.previous_hash, + 'hash': block.hash + }) + with open('blockchain.json', 'w') as file: + json.dump(chain_data, file) + + def is_chain_valid(self): + for i in range(1, len(self.chain)): + current_block = self.chain[i] + previous_block = self.chain[i - 1] + + if current_block.hash != current_block.calculate_hash(): + return False + + if current_block.previous_hash != previous_block.hash: + return False + + return True + +app = Flask(__name__) +app.secret_key = 'lesecretkey' +blockchain = Blockchain() +CONNECTED_NODES = [] + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/upload', methods=['POST']) +def upload_image(): + file = request.files['image'] + image_data = base64.b64encode(file.read()).decode('utf-8') + current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + block = Block(len(blockchain.chain), current_time, image_data, blockchain.get_latest_block().hash) + blockchain.add_block(block) + + if blockchain.is_chain_valid(): + flash('Image uploaded successfully', 'success') + else: + flash('Corrupted blocks detected. Image upload failed.', 'danger') + blockchain.chain.pop() + + return redirect(url_for('index')) + +@app.route('/chain', methods=['GET']) +def get_chain(): + chain_data = [] + for block in blockchain.chain: + chain_data.append({ + 'index': block.index, + 'timestamp': block.timestamp, + 'data': block.data, + 'previous_hash': block.previous_hash, + 'hash': block.hash + }) + return jsonify(chain_data) + +@app.route('/register_node', methods=['POST']) +def register_node(): + node_url = request.form['node_url'] + if not node_url.startswith('http://') and not node_url.startswith('https://'): + node_url = 'http://' + node_url + if node_url not in CONNECTED_NODES: + CONNECTED_NODES.append(node_url) + return redirect(url_for('index')) + +@app.route('/sync_chain', methods=['GET']) +def sync_chain(): + longest_chain = None + current_len = len(blockchain.chain) + + for node_url in CONNECTED_NODES: + response = requests.get(f'{node_url}/chain') + if response.status_code == 200: + chain_data = response.json() + chain_len = len(chain_data) + if chain_len > current_len: + current_len = chain_len + longest_chain = chain_data + + if longest_chain: + blockchain.chain = [Block(block['index'], block['timestamp'], block['data'], block['previous_hash']) for block in longest_chain] + blockchain.save_chain() + flash('Blockchain synchronized successfully', 'success') + else: + flash('Blockchain is already up to date', 'info') + + return redirect(url_for('index')) + +@app.route('/validate', methods=['GET']) +def validate_blockchain(): + is_valid = blockchain.is_chain_valid() + if is_valid: + return jsonify({"message": "Blockchain is valid"}) + else: + return jsonify({"message": "Blockchain is invalid"}), 400 + +@app.route('/nodes', methods=['GET']) +def get_nodes(): + return jsonify(CONNECTED_NODES) + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..023ec63 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests +flask \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..0713418 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,81 @@ + + + + Memechain + + + +
+

Memechain

+ your glorified nfts or something + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+
+ + +
+ +
+
+

Connected Nodes

+
+
+ + +
+ +
+ +
+ Sync Blockchain +
+

Blockchain

+
+
+ + + + + + + \ No newline at end of file