In this article, we are going to implement a simple and plain “smart blockchain” with Python language and compare it with a blockchain. We hope that by doing this, the main concepts and advantages of this technology will be more clearly specified and welcomed by the developers and the blockchain community.
Before you start, consider the following points:
We assume that the reader is familiar with the Python language and comprehend blockchain concepts, hash, and so on. For this reason and to avoid getting the story long and tedious, we’re focusing on “smart blockchain” features. Of course, if you forgot some of the concepts of blockchain, you can refer to the following article. In this article, the author has fully implemented a blockchain with Python. We also use his ideas and codes to implement “smart blockchain” so that we can easily compare “smart blockchain” with blockchain.
https://hackernoon.com/learn-blockchains-by-building-one-117428612f46
Our Python version is Python 3.7 and we use Spyder-Anaconda3 as the IDE. You can use your favorite IDE like PyCharm and so on. Of course, for example, Jupyter Notebook is not suitable for this purpose. We will also use Postman, but you can also use cURL
Understand the functionality of “smart blockchain” through coding.
new_block, new_transaction, last_block, hash
import hashlib
import json
from time import time
class Smart_Blockchain:
def __init__(self):
self.current_transactions = []
self.chain = []
# Create the genesis block
self.new_block(previous_hash='1')
def new_block(self, previous_hash):
"""
Create a new Block in the Smart Blockchain
:param previous_hash: Hash of previous Block
:return: New Block
"""
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
# Reset the current list of transactions
self.current_transactions = []
self.chain.append(block)
return block
def new_transaction(self, sender, amount, recipient):
"""
Creates a new transaction to go into the next mined Block
:param sender: Address of the Sender
:param amount_send: The amount sent by the sender
:param bpsc: Address of the Smart contract (bpsc)
:param amount_bpsc: The amount received by bpsc (Transaction fees)
:param recipient: Address of the Recipient
:param amount_receive: The amount received by the recipient
:return: The index of the Block that will hold this transaction
"""
self.current_transactions.append({
'sender': sender,
'amount_send': amount,
'bpsc': 'bpsc_wallet_address', # Block Producer Smart Contract (bpsc)
'amount_bpsc': amount * 0.00005, # Transaction fees
'recipient': recipient,
'amount_receive': amount * 0.99995,
})
return self.last_block['index'] + 1
@property
def last_block(self):
return self.chain[-1]
@staticmethod
def hash(block):
"""
Creates a SHA-256 hash of a Block
:param block: Block
"""
# We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
/transactions/new
Request to build a new transaction and add it to a block
/mine
Ask our server to mine a new block
/chain
Request to return a complete list of blocks
import hashlib
import json
from time import time
from urllib.parse import urlparse
from flask import Flask, jsonify, request
class Smart_Blockchain:
# .....
# .....
# .....
# Instantiate the Node
app = Flask(__name__)
# Instantiate the Smart_Blockchain
blockchain = Smart_Blockchain()
@app.route('/mine', methods=['GET'])
def mine():
last_block = blockchain.last_block
# Forge the new Block by adding it to the chain
previous_hash = blockchain.hash(last_block)
block = blockchain.new_block(previous_hash)
response = {
'message': "New Block Forged",
'index': block['index'],
'transactions': block['transactions'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 200
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
values = request.get_json()
# Check that the required fields are in the POST'ed data
required = ['sender', 'amount', 'recipient']
if not all(k in values for k in required):
return 'Missing values', 400
# Create a new Transaction
index = blockchain.new_transaction(values['sender'], values['amount'], values['recipient'])
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
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port
app.run(host='0.0.0.0', port=port)
import sys
.....
if __name__ == '__main__':
app.run(host='0.0.0.0', port=sys.argv[1])
http://localhost:5000/transactions/new
The information for this transaction must be entered in the Body section, and obviously, we select raw and then JSON.
This will create the next block. The content of each block includes all performed transactions and pending ones, for instance, here, the second block is created that contains only one transaction.
http://localhost:5000/chain
The decentralized network for “smart blockchain”
/nodes/register
import hashlib
import json
from time import time
from urllib.parse import urlparse
from flask import Flask, jsonify, request
class Smart_Blockchain:
def __init__(self):
self.current_transactions = []
self.chain = []
self.nodes = set()
# Create the genesis block
self.new_block(previous_hash='1')
def register_node(self, address):
"""
Add a new node to the list of nodes
:param address: Address of node. Eg. 'http://192.168.0.5:5000'
"""
parsed_url = urlparse(address)
if parsed_url.netloc:
self.nodes.add(parsed_url.netloc)
elif parsed_url.path:
# Accepts an URL without scheme like '192.168.0.5:5000'.
self.nodes.add(parsed_url.path)
else:
raise ValueError('Invalid URL')
.......
@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
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port
app.run(host='0.0.0.0', port=port)
/smart/chain
import hashlib
import json
from time import time
from urllib.parse import urlparse
import requests
from flask import Flask, jsonify, request
class Smart_Blockchain:
def __init__(self):
self.current_transactions = []
self.chain = []
self.nodes = set()
# Create the genesis block
self.new_block(previous_hash='1')
def smart_chain(self):
"""
All nodes can receive the smart_chain
"""
schain = None
response = requests.get(f'http://127.0.0.1:5000/chain')
if response.status_code == 200:
chain = response.json()['chain']
schain = chain
# Replace our chain
if schain:
self.chain = schain
return True
return False
.......
@app.route('/smart/chain', methods=['GET'])
def smart_chain():
replaced = blockchain.smart_chain()
if replaced:
response = {
'message': 'Smart chain update by bpsc',
'smart chain': blockchain.chain,
'length': len(blockchain.chain)
}
else:
response = {
'message': 'Unsuccessful: Please try again',
'old chain': blockchain.chain,
'length': len(blockchain.chain)
}
return jsonify(response), 200
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port
app.run(host='0.0.0.0', port=port)
http://localhost:5000
Which acts as a smart contract (BPSC).
http://localhost:5001
One of the networks’ nodes that acts as a token sender.
http://localhost:5002
One of the networks’ nodes that acts as a token receiver.
http://localhost:5001/nodes/register
http://localhost:5001/smart/chain
By doing this, the node with port 5001 will receive the last chain from (BPSC). Thus, the node’s chain replaced with the latest chain created by (BPSC).
Dozens of “smart blockchains” on a decentralized network
import hashlib
import json
from time import time
from urllib.parse import urlparse
import requests
from flask import Flask, jsonify, request
class Smart_Blockchain:
def __init__(self):
self.current_information = []
self.chain = []
self.chain2 = []
self.nodes = set()
# Create the genesis block
self.new_block(previous_hash='1')
def register_node(self, address):
"""
Add a new node to the list of nodes
:param address: Address of node. Eg. 'http://192.168.0.5:5000'
"""
parsed_url = urlparse(address)
if parsed_url.netloc:
self.nodes.add(parsed_url.netloc)
elif parsed_url.path:
# Accepts an URL without scheme like '192.168.0.5:5000'.
self.nodes.add(parsed_url.path)
else:
raise ValueError('Invalid URL')
def smart_chain(self):
"""
All nodes can receive the smart_chain
"""
schain = None
response = requests.get(f'http://127.0.0.1:5000/chain')
if response.status_code == 200:
chain = response.json()['chain']
schain = chain
# Replace our chain
if schain:
self.chain = schain
return True
return False
def new_block(self, previous_hash):
"""
Create a new Block in the Smart Blockchain
:param previous_hash: Hash of previous Block
:return: New Block
"""
block = {
'index2': len(self.chain2) + 1,
'timestamp': time(),
'information': self.current_information,
'previous_hash': previous_hash or self.hash(self.chain2[-1]),
}
# Reset the current list of transactions
self.current_information = []
self.chain2.append(block)
return block
def new_information(self, information):
"""
Creates a new information
:param information: Your information
:return: The index of the Block that will hold this information
"""
self.current_information.append({'information': information })
return self.last_block['index2'] + 1
@property
def last_block(self):
return self.chain2[-1]
@staticmethod
def hash(block):
"""
Creates a SHA-256 hash of a Block
:param block: Block
"""
# We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
# Instantiate the Node
app = Flask(__name__)
# Instantiate the Smart_Blockchain
blockchain = Smart_Blockchain()
@app.route('/mine', methods=['GET'])
def mine():
last_block = blockchain.last_block
# Forge the new Block by adding it to the chain
previous_hash = blockchain.hash(last_block)
block = blockchain.new_block(previous_hash)
response = {
'message': "New Block Forged",
'index2': block['index2'],
'information': block['information'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 200
@app.route('/information/new', methods=['POST'])
def new_information():
values = request.get_json()
# Check that the required fields are in the POST'ed data
required = ['information']
if not all(k in values for k in required):
return 'Missing values', 400
# Create a new information
index = blockchain.new_information(values['information'])
response = {'message': f'information will be added to Block {index}'}
return jsonify(response), 201
@app.route('/chain2', methods=['GET'])
def full_chain2():
response = {
'chain2': blockchain.chain2,
'length': len(blockchain.chain2),
}
return jsonify(response), 200
@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('/smart/chain', methods=['GET'])
def smart_chain():
replaced = blockchain.smart_chain()
if replaced:
response = {
'message': 'Smart chain update by bpsc',
'smart chain': blockchain.chain,
'length': len(blockchain.chain)
}
else:
response = {
'message': 'Unsuccessful: Please try again',
'old chain': blockchain.chain,
'length': len(blockchain.chain)
}
return jsonify(response), 200
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-p', '--port', default=5001, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port
app.run(host='0.0.0.0', port=port)
http://localhost:5001/information/new
http://localhost:5001/mine
http://localhost:5001/chain2
By doing this test, we make sure that the two blocks are in the second chain of our server, and the second chain has no relation with the first chain.
http://localhost:5000/transactions/new
http://localhost:5000/mine
http://localhost:5001/smart/chain
Planning and scheduling for mining and producing operations a block in a “smart blockchain”
A — based on time, build a new block, for example, every second or every minute.
B — based on the number of transactions; for example, after every ten transactions or one hundred transactions.
C — a combination of methods A and B; for example, ten seconds or ten transactions, each occurring sooner.
..........
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
values = request.get_json()
# Check that the required fields are in the POST'ed data
required = ['sender', 'amount', 'recipient']
if not all(k in values for k in required):
return 'Missing values', 400
# Create a new Transaction
index = blockchain.new_transaction(values['sender'], values['amount'], values['recipient'])
response = {'message': f'Transaction will be added to Block {index}'}
last_block = blockchain.last_block
# Forge the new Block by adding it to the chain
previous_hash = blockchain.hash(last_block)
block = blockchain.new_block(previous_hash)
response = {
'message': "New Block Forged",
'index': block['index'],
'transactions': block['transactions'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 201
..........
http://localhost:5000/transactions/new
(BPSC) immediately makes both the transaction and mining a block and adds it to the chain.
only an empty block will be minded because no transaction is expected.
Summary and conclusion:
This version is according to “Smart Blockchain” technology and final. Although these nodes cannot produce blocks, they can do their transactions through (BPSC) and also receive the last chain from (BPSC).
This is also final, but in this version, we have added a new feature to the previous version. It means a simple blockchain (To store personal data) has been added to the previous code.
How To Build a Smart Blockchain That Prevents Double Spending: A Step-by-Step Guide
The last word
- Cambridge Bitcoin Electricity Consumption Index
Also, if you have any questions or you see any ambiguities or errors in this article, please let us know.