Created
December 29, 2017 14:24
-
-
Save meganehouser/341b1f2e3ba56d92ebf1dc57ceca22da to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
import hashlib | |
import json | |
from textwrap import dedent | |
from time import time | |
from uuid import uuid4 | |
from urllib.parse import urlparse | |
from flask import Flask, jsonify, request | |
data Transaction(sender: str, recipient: str, amount: int) | |
data Block(index: int, | |
timestamp: float, | |
transactions: List[transactions], | |
proof: int, | |
previous_hash: str) | |
data BlockChain(chain:list, current_transactions:List[Transaction], nodes): | |
@classmethod | |
def create(self): | |
return BlockChain.add_block(BlockChain([], [], set()), proof=100, previous_hash=1) | |
@property | |
def last_block(self): | |
return self.chain[-1] | |
@property | |
def next_index(self): | |
return self.last_block.index + 1 | |
@classmethod | |
def register_node(self, BlockChain(chain, trans, nodes), address): | |
parsed_url = parse(address) | |
nodes.add(parsed_url.netloc) | |
return BlockChain(chain, trans, nodes) | |
@classmethod | |
def add_block(self, BlockChain(chain, trans, nodes), proof, previous_hash=None): | |
""" | |
ブロックチエーンに新しいブロックを作る | |
""" | |
index = len(chain) + 1 | |
p_hash = previous_hash or BlockChain.hash(chain[-1]) | |
block = Block(index, time(), trans, proof, p_hash) | |
chain.append(block) | |
return BlockChain(chain, [], nodes) | |
@classmethod | |
def add_transaction(self, BlockChain(c, curr, nodes), sender, recipient, amount): | |
""" | |
次に採掘されるブロックに加える新しいトランザクションをつくる | |
""" | |
tran = Transaction(sender, recipient, amount) | |
curr.append(tran) | |
return BlockChain(c, curr, nodes) | |
@classmethod | |
def hash(self, block): | |
block_string = json.dumps(block, sort_keys=True).encode() | |
return hashlib.sha256(block_string).hexdigest() | |
def valid_chain(chain): | |
""" | |
ブロックチェーンが正しいかを確認する | |
""" | |
last_block = chain[0] | |
current_index = 1 | |
while current_index < len(chain): | |
block = chain[current_index] | |
print(last_block) | |
print(block) | |
print("\n----------------\n") | |
if block.previous_hash != BlockChain.hash(last_block) | |
return False | |
if not valid_proof(last_block.proof, block.proof) | |
return False | |
last_block = block | |
current_index += 1 | |
return True | |
def resolve_conflicts(BlockChain(chain, trans, nodes)): | |
""" | |
ネットワーク上の最も長いチェーンで自らを置き換えることでコンフリクトを解決する | |
""" | |
neighbours = nodes | |
new_chain = None | |
max_length = len(chian) | |
for node in neighbours: | |
response = request.get("http://{}/chain".format(node)) | |
if response.status_code == 200: | |
length = response.json()['length'] | |
chain = response.json()['chain'] | |
if length > max_length and valid_chain(chain): | |
max_length = length | |
new_chain = chain | |
if new_chain: | |
chain = new_chain | |
return True, BlockChain(chain, trans, nodes) | |
return False, BlockChain(chain, trans, nodes) | |
def proof_of_work(last_proof): | |
""" | |
プルーフ・オブ・ワークのアルゴリズム | |
- hash(pp')の最初の4つが0となるような p' を探す | |
- p は前のプルーフ、p'は新しいプルーフ | |
""" | |
proof = 0 | |
while valid_proof(last_proof, proof) is False: | |
proof += 1 | |
return proof | |
def valid_proof(last_proof, proof): | |
""" | |
プルーフが正しいか確認する | |
""" | |
guess = "{}{}".format(last_proof, proof).encode() | |
guess_hash = hashlib.sha256(guess).hexdigest() | |
return guess_hash[:4] == "0000" | |
app = Flask(__name__) | |
node_identifier = str(uuid4()).replace('-', '') | |
blockchain = BlockChain.create() | |
@app.route('/transactions/new', methods=['POST']) | |
def new_transactions(): | |
values = request.get_json() | |
required = ['sender', 'recipient', 'amount'] | |
if not all(k in values for k in required): | |
return 'Missing values', 400 | |
global blockchain | |
blockchain = BlockChain.add_transaction(blockchain, values['sender'], values['recipient'], values['amount']) | |
index = blockchain.next_index | |
response = {'message': "トランザクションは{}に追加されました。".format(index)} | |
return jsonify(response), 201 | |
@app.route('/mine', methods=['GET']) | |
def mine(): | |
global blockchain | |
last_block = blockchain.last_block | |
last_proof = last_block.proof | |
proof = proof_of_work(last_proof) | |
blockchain = BlockChain.add_transaction(blockchain, sender="0", | |
recipient=node_identifier, | |
amount=1) | |
blockchain = BlockChain.add_block(blockchain, proof) | |
block = blockchain.last_block | |
response = { | |
'message': "新しいブロックを採掘しました", | |
'index': block.index, | |
'transactions': block.transactions, | |
'proof': block.proof, | |
'previous_hash': block.previous_hash, | |
} | |
return jsonify(response), 200 | |
@app.route('/chain', methods=['GET']) | |
def full_chian(): | |
global blockchain | |
response = { | |
'chain': blockchain.chain, | |
'length': len(blockchain.chain), | |
} | |
return jsonify(response), 200 | |
@app.route('/node/register', methods=['POST']) | |
def register_node(): | |
global blockchain | |
values = request.get_json() | |
nodes = values.get('nodes') | |
if nodes is None: | |
return "Error: 有効ではないノードのリストです", 400 | |
for node in nodes: | |
blockchain = BlockChain.register_node(blockchain, node) | |
response = { | |
'message': '新しいノードが追加されました', | |
'total_nodes': list(blockchain.nodes) | |
} | |
return jsonify(response), 201 | |
@app.route('/nodes/resolve', methods=['GET']) | |
def consensus(): | |
global blockchain | |
replaced, new_blockchain = resolve_conflicts(blockchain) | |
if replaced: | |
blockchain = new_blockchain | |
response = { | |
'message': 'チェーンが置き換えられました', | |
'new_chain': blockchain.chain | |
} | |
else: | |
response = { | |
'message': 'チェーンが確認されました', | |
'chain': blockchain.chain | |
} | |
return jsonify(response), 200 | |
if __name__ == '__main__': | |
app.run(host='127.0.0.1', port=5000, debug=True) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment