Blockchain with Vue, Python & Flask
Irena Popova π©π»βπ»
Posted on October 25, 2024
Creating a complete blockchain application with a Vue.js frontend and a Python backend.
Let's outline the basic components and provide some example code snippets to get you started.
Overview
- 1. Backend (Python with Flask) Create a simple blockchain structure. Set up a Flask API to interact with the blockchain.
- 2. Frontend (Vue.js)
- Create a Vue.js application that communicates with the Flask API.
- Display blockchain data and allow user interactions (like adding a new block). Step 1: Setting Up the Backend
- Install Flask: Make sure you have Flask installed. You can do this using pip:
Setting up the environment
pip install Flask
- Create a Basic Blockchain Class:
# blockchain.py
import hashlib
import json
from time import time
from flask import Flask, jsonify, request
class Blockchain:
def __init__(self):
self.chain = []
self.current_transactions = []
self.new_block(previous_hash='1', proof=100)
def new_block(self, proof, previous_hash=None):
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
self.current_transactions = []
self.chain.append(block)
return block
def new_transaction(self, sender, recipient, amount):
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
@staticmethod
def hash(block):
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
@property
def last_block(self):
return self.chain[-1]
app = Flask(__name__)
blockchain = Blockchain()
@app.route('/mine', methods=['POST'])
def mine():
values = request.get_json()
required = ['proof', 'sender', 'recipient']
if not all(k in values for k in required):
return 'Missing values', 400
index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])
blockchain.new_block(values['proof'])
response = {
'message': f'New Block Forged',
'index': index,
'block': blockchain.last_block,
}
return jsonify(response), 200
@app.route('/chain', methods=['GET'])
def full_chain():
response = {
'chain': blockchain.chain,
'length': len(blockchain.chain),
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(debug=True)
Step 2: Setting Up the Frontend
- Create a Vue.js App: If you haven't created a Vue.js project yet, you can do so using Vue CLI:
vue create my-blockchain-app
- Install Axios for API Calls:
npm install axios
- Create a Simple Component:
// src/components/Blockchain.vue
<template>
<div>
<h1>Blockchain</h1>
<button @click="fetchChain">Fetch Blockchain</button>
<ul>
<li v-for="block in blockchain" :key="block.index">
Block #{{ block.index }} - {{ block.timestamp }}
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
blockchain: []
};
},
methods: {
fetchChain() {
axios.get('http://localhost:5000/chain')
.then(response => {
this.blockchain = response.data.chain;
})
.catch(error => {
console.error(error);
});
}
}
};
</script>
Step 3: Putting It All Together
Run the Flask Backend: Make sure your Python server is running:
python blockchain.py
Run the Vue.js Frontend: Now, run your Vue.js application:
npm run serve
Letβs enhance the blockchain application by adding more advanced features such as:
- Proof of Work Mechanism: Implement a basic proof of work algorithm.
- Transaction Pool: Allow users to create transactions and see them in a pool before mining. -Node Discovery: Allow multiple nodes to connect and share the blockchain. -Improved Frontend: Create a more interactive UI for displaying the blockchain and transactions. Step 1: Enhancing the Backend
- Update the Blockchain Class We will implement a basic Proof of Work algorithm and a transaction pool.
# blockchain.py
import hashlib
import json
from time import time
from flask import Flask, jsonify, request
from urllib.parse import urlparse
import requests
class Blockchain:
def __init__(self):
self.chain = []
self.current_transactions = []
self.nodes = set()
self.new_block(previous_hash='1', proof=100)
def new_block(self, proof, previous_hash=None):
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
self.current_transactions = []
self.chain.append(block)
return block
def new_transaction(self, sender, recipient, amount):
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
@staticmethod
def hash(block):
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
@property
def last_block(self):
return self.chain[-1]
def proof_of_work(self, last_proof):
proof = 0
while not self.valid_proof(last_proof, proof):
proof += 1
return proof
@staticmethod
def valid_proof(last_proof, proof):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000" # Adjust difficulty here
def register_node(self, address):
parsed_url = urlparse(address)
self.nodes.add(parsed_url.netloc)
def resolve_conflicts(self):
neighbours = self.nodes
new_chain = None
max_length = len(self.chain)
for node in neighbours:
response = requests.get(f'http://{node}/chain')
if response.status_code == 200:
length = response.json()['length']
chain = response.json()['chain']
if length > max_length and self.valid_chain(chain):
max_length = length
new_chain = chain
if new_chain:
self.chain = new_chain
return True
return False
def valid_chain(self, chain):
last_block = chain[0]
current_index = 1
while current_index < len(chain):
block = chain[current_index]
if block['previous_hash'] != self.hash(last_block):
return False
if not self.valid_proof(last_block['proof'], block['proof']):
return False
last_block = block
current_index += 1
return True
app = Flask(__name__)
blockchain = Blockchain()
@app.route('/mine', methods=['POST'])
def mine():
values = request.get_json()
required = ['sender', 'recipient']
if not all(k in values for k in required):
return 'Missing values', 400
last_block = blockchain.last_block
last_proof = last_block['proof']
proof = blockchain.proof_of_work(last_proof)
blockchain.new_transaction(sender=values['sender'], recipient=values['recipient'], amount=1)
previous_hash = blockchain.hash(last_block)
block = blockchain.new_block(proof, previous_hash)
response = {
'message': 'New Block Forged',
'index': block['index'],
'block': block,
}
return jsonify(response), 200
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
values = request.get_json()
required = ['sender', 'recipient', 'amount']
if not all(k in values for k in required):
return 'Missing values', 400
index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])
response = {'message': f'Transaction will be added to Block {index}'}
return jsonify(response), 201
@app.route('/chain', methods=['GET'])
def full_chain():
response = {
'chain': blockchain.chain,
'length': len(blockchain.chain),
}
return jsonify(response), 200
@app.route('/nodes/register', methods=['POST'])
def register_nodes():
values = request.get_json()
nodes = values.get('nodes')
if nodes is None:
return 'Error: Please supply a valid list of nodes', 400
for node in nodes:
blockchain.register_node(node)
response = {
'message': 'New nodes have been added',
'total_nodes': list(blockchain.nodes),
}
return jsonify(response), 201
@app.route('/nodes/resolve', methods=['GET'])
def consensus():
replaced = blockchain.resolve_conflicts()
if replaced:
response = {
'message': 'Our chain was replaced',
'new_chain': blockchain.chain,
}
else:
response = {
'message': 'Our chain is authoritative',
'chain': blockchain.chain,
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(debug=True)
Step 2: Enhancing the Frontend
- Create a Transaction Form in Vue.js We will now create a form for users to submit transactions.
// src/components/Blockchain.vue
<template>
<div>
<h1>Blockchain</h1>
<button @click="fetchChain">Fetch Blockchain</button>
<h2>Transactions</h2>
<form @submit.prevent="submitTransaction">
<input type="text" v-model="sender" placeholder="Sender" required />
<input type="text" v-model="recipient" placeholder="Recipient" required />
<input type="number" v-model="amount" placeholder="Amount" required />
<button type="submit">Send Transaction</button>
</form>
<h2>Blockchain</h2>
<ul>
<li v-for="block in blockchain" :key="block.index">
Block #{{ block.index }} - {{ block.timestamp }}
<ul>
<li v-for="transaction in block.transactions" :key="transaction.sender">
{{ transaction.sender }} -> {{ transaction.recipient }}: {{ transaction.amount }}
</li>
</ul>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
blockchain: [],
sender: '',
recipient: '',
amount: 0,
};
},
methods: {
fetchChain() {
axios.get('http://localhost:5000/chain')
.then(response => {
this.blockchain = response.data.chain;
})
.catch(error => {
console.error(error);
});
},
submitTransaction() {
const transaction = {
sender: this.sender,
recipient: this.recipient,
amount: this.amount,
};
axios.post('http://localhost:5000/transactions/new', transaction)
.then(response => {
alert(response.data.message);
this.fetchChain(); // Refresh the blockchain view
})
.catch(error => {
console.error(error);
});
}
}
};
</script>
Step 3: Node Discovery and Consensus
You can test your blockchain with multiple nodes by running several instances of your Flask app on different ports. For example, you can run:
FLASK_RUN_PORT=5001 python blockchain.py
Then, you can register nodes using a POST request:
curl -X POST -H "Content-Type: application/json" -d '{"nodes": ["localhost:5001"]}' http://localhost:5000/nodes/register
This more advanced blockchain application includes:
-Proof of Work: A basic mechanism to mine new blocks.
-Transaction Pool: Users can create transactions before they are mined.
-Node Discovery: Support for multiple nodes and a consensus mechanism.
-Interactive Frontend: A Vue.js UI for submitting transactions and viewing the blockchain.
Happy coding!
Posted on October 25, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.