def add_block(): block_dict = request.values.to_dict() block = Block(**block_dict) chain = BlockChain() last_block = chain.get_last_block() if ProofOfWork(block, last_block).is_block_valid(): chain.add_block(block) return jsonify(received=True)
def mine_block(args): blockchain = BlockChain() utxo_set = UTXOSet(blockchain) utxo_tx = UTXOTx(args.From, args.to, args.amount, utxo_set) coin_base_tx = CoinBaseTx(blockchain.address) blockchain.add_block([coin_base_tx, utxo_tx]) utxo_set.update(blockchain.last_block) print('Done!')
def cli_sending(From, To, amount): blk_chain = BlockChain() if not blk_chain.Verify_Block_Chain(): print("Your database may be damaged. Cannot open this database.") return tx = transaction.NewUTXOTransaction(From, To, amount, blk_chain) if tx == None: print("Error: not enough funds") return blk_chain.add_block(tx) print("From: {f}\nTo: {t}\nAmount: {a}".format(f=From, t=To, a=amount))
def create_chain_from_dump(chain_dump): gen_blockchain = BlockChain() gen_blockchain.build_genesis() for idx, block_data in enumerate(chain_dump): if idx == 0: continue # skip genesis block block = Block(block_data["index"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"], block_data["nonce"]) proof = block_data['hash'] added = gen_blockchain.add_block(block, proof) if not added: raise Exception("The chain dump is tampered") return gen_blockchain
def create_chain_from_dump(self,chain_dump): new_blockchain = BlockChain(consts.difficulty) for idx, block_data in enumerate(chain_dump): block = Block(block_data["id"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"], block_data["nonce"]) block.hash = block_data['hash'] if idx > 0: added = new_blockchain.add_block(block) if not added: raise Exception("The chain dump is tampered!!") else: # the block is a genesis block, no verification needed new_blockchain.chain.append(block) return new_blockchain
def create_chain_from_dump(chain_dump): blockchain = BlockChain() for index, block_data in enumerate(chain_dump): block = Block( block_data["index"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"] ) proof = block_data["hash"] if index > 0: added = blockchain.add_block(block, proof) if not added: raise Exception("The chain dump is tampered!!") else: # the block is a genesis block, no verification needed blockchain.chain.append(block) return blockchain pass
class BlockChainTests(unittest.TestCase): def setUp(self): self.chain = BlockChain() def test_is_valid_genesis_correctness(self): genesis = self.chain.get_latest_block() fake_genesis = Block( 0, hashlib.sha256( str(round(time.time() * 1000)).encode('utf-8') + b"The Genesis block"), None, int(round(time.time() * 1000)), "The Genesis block") self.assertTrue(self.chain.is_valid_genesis(genesis)) self.assertFalse(self.chain.is_valid_genesis(fake_genesis)) def test_is_valid_new_block_correctness(self): timestamp = str(round(time.time() * 1000)) previous_block = self.chain.get_latest_block() correct_block = Block( 1, self.chain.calculate_hash(1, previous_block.hash, timestamp, "The correct block"), self.chain.get_latest_block().hash, int(round(time.time() * 1000)), "The correct block") incorrect_index = Block( 2, self.chain.calculate_hash(2, previous_block.hash, timestamp, "The incorrect block"), self.chain.get_latest_block().hash, int(round(time.time() * 1000)), "The incorrect block") incorrect_hash = Block( 1, self.chain.calculate_hash( 1, hashlib.sha256('hi'.encode('utf-8')).hexdigest(), timestamp, "The correct block"), self.chain.get_latest_block().hash, int(round(time.time() * 1000)), "The correct block") self.assertTrue( self.chain.is_valid_new_block(correct_block, self.chain.get_latest_block())) self.assertFalse( self.chain.is_valid_new_block(incorrect_index, self.chain.get_latest_block())) self.assertFalse( self.chain.is_valid_new_block(incorrect_hash, self.chain.get_latest_block())) def test_generate_next_block_correctness(self): next_block = self.chain.generate_next_block('new data') previous_block = self.chain.get_latest_block() self.assertEqual(next_block.data, 'new data') self.assertEqual(next_block.index, previous_block.index + 1) self.assertEqual( next_block.hash, self.chain.calculate_hash(next_block.index, previous_block.hash, next_block.timestamp, next_block.data)) def test_adding_correct_block(self): next_block = self.chain.generate_next_block('new data') self.chain.add_block(next_block) latest_block = self.chain.get_latest_block() self.assertEqual(len(self.chain), 2) self.assertEqual(latest_block.index, next_block.index) self.assertEqual(latest_block.hash, next_block.hash) self.assertEqual(latest_block.data, next_block.data) self.assertEqual(latest_block.timestamp, next_block.timestamp) self.assertEqual(latest_block.previous_hash, next_block.previous_hash) def test_adding_incorrect_block(self): next_block = self.chain.generate_next_block('new data') self.chain.add_block(next_block) incorrect_block = Block( 2, hashlib.sha256('wrong'.encode('utf-8')).hexdigest(), next_block.hash, int(round(time.time() * 1000)), "Not correct block") self.chain.add_block(incorrect_block) self.assertEqual(len(self.chain), 2)
class Peer(threading.Thread): """Peer class. A separate thread for a peer, which simulates all the functionalities of a peer. """ def __init__(self, pid, get_delay, gen_block): threading.Thread.__init__(self) self.pid = pid self._get_delay = get_delay self._connected_peers_ptrs = {} self._semaphore = threading.Semaphore(0) self._queue = Queue.Queue() self._recvd_or_sent = defaultdict(set) # obj id to set of senders # Block self._blockchain = BlockChain(gen_block, self.pid) self._block_timer = None # the random no denotes the computation power of the peer. lower the random no, higher the comp. power. self._block_gen_mean = Parameters.block_gen_mean * (random.uniform( 0.5, 1.0)) #(2)**(-int(pid[2:]))# def add_connected_peer(self, peer_id, receiver_func_ptr): self._connected_peers_ptrs[peer_id] = receiver_func_ptr def gen_transaction(self): """ Generates transactions after expovariant intervals Spawned as a new thread, which keeps running in parallel. """ while True: waiting_time = random.expovariate(1.0 / Parameters.txn_gen_mean) # Sleep for waiting_time time.sleep(waiting_time) # Sanity check if Parameters.num_peers <= 1: print "Too few peers" continue # Randomly generate receiver self_id_int = int(self.pid[2:]) receiver = "P_" + str( random.choice( range(0, self_id_int) + range(self_id_int + 1, Parameters.num_peers))) # create txn, message curr_balance = self._blockchain.get_current_balance() amt = random.randint(0, curr_balance) t = Transaction(self.pid, receiver, amt) msg = Message(t, self.pid, False) # Put message in queue to be processed self._queue.put(msg) self._semaphore.release() def _gen_block(self): """gen_block helper""" block = self._blockchain.generate_block() msg = Message(block, self.pid, True) self._queue.put(msg) self._semaphore.release() print Parameters.a[ self. pid] + "Block generated ", block.id, " by peer ", self.pid, " having ", len( block.transactions), " txns" + Parameters.a[Parameters.MAX] self.gen_block() def gen_block(self): """ Generates new block at expovarient intervals Creates timer for calling _gen_block Timer object can be cancelled on receiving a new block _gen_block again calls this function on successfully creating block """ waiting_time = random.expovariate(1.0 / (self._block_gen_mean)) # Tk self._block_timer = threading.Timer(waiting_time, self._gen_block) self._block_timer.start() def receive_message(self, message): """Every connected peer has a ptr to this function""" self._queue.put(message) self._semaphore.release() def process_message(self, message): """Process message from queue""" # add to received objects msg_set = self._recvd_or_sent[message.content.id] msg_set.add(message.sender) new_message = Message(message.content, self.pid, message.is_block) # print "Processing message id {} by peer {} sent by {}".format(message.content.id, self.pid, message.sender) # Process as per type of message if not message.is_block: self._blockchain.add_transaction(message.content) else: if self._blockchain.add_block(message.content): self._block_timer.cancel() self.gen_block() self._blockchain.print_longest_chain() # send to connected peers, with conditions for p in self._connected_peers_ptrs: if p not in msg_set: # send to this! msg_set.add(p) p_recv_ptr = self._connected_peers_ptrs[p] delay = self._get_delay(self.pid, p, message.is_block) new_message.send(p_recv_ptr, delay) def run(self): """Thread run""" print "Starting Peer ", self.pid thread.start_new_thread(self.gen_transaction, ()) self.gen_block() # Process messages from queue while True: self._semaphore.acquire() self.process_message(self._queue.get()) def write_to_file(self): """ Helper function to write the peer's details & its block tree to a file. """ write_string = "" write_string += "Peer ID : " + self.pid + "\n" write_string += self._blockchain.write_to_file() # print write_string return write_string """ Helper functions for visualizing the block tree of the peer. """ def render(self): postfix = "(" + self.get_postorder_string() + ")" + self.pid return postfix # Render helper def get_postorder_string(self): b_chain = self._blockchain._all_blocks.values() tree = {} for b in b_chain: if b.previous not in tree: tree[b.previous] = [] tree[b.previous].append(b.id) return self.get_postorder("B_1", tree) # Render helper def get_postorder(self, cur, tree): sub_ans = "" if cur in tree.keys(): sub_ans = "(" for i in tree[cur]: sub_ans += self.get_postorder(i, tree) + "," sub_ans = sub_ans[:-1] sub_ans += (")" + cur) else: sub_ans = cur return sub_ans
class Node(object): __slots__ = [ "nodes", "connections", "app", "chain", "session", "addr", "port" ] MASTER = ("localhost", DEFAULT_PORT) # FIX localhost to real ip def __init__(self, addr, port=DEFAULT_PORT, *, master=False): self.addr = addr self.port = port self.nodes = [Node.MASTER] self.connections = [] self.app = web.Application() self.chain = BlockChain() self.session = None if master == False: loop = asyncio.get_event_loop() loop.run_until_complete(self._init()) # just for check with web-browser self.app.router.add_get("/query_node_list", self.response_node_list) self.app.router.add_get("/query_block_chain", self.response_block_chain) # blockchain node do self.app.router.add_get("/ws", self.ws_handler) async def _init(self): await self.query_nodes() await self.connect_to_peers(self.nodes) await self.register_node() async def register_node(self): msg = json.dumps({ 'type': MessageType.REGISTER_ME, 'nodeinfo': (self.addr, self.port) }) await self.broadcast(msg) async def query_nodes(self): if self.session == None: self.session = aiohttp.ClientSession() ws = await self.session.ws_connect( "http://{}:{}/ws".format(*Node.MASTER)) await ws.send_str(json.dumps({'type': MessageType.REQUEST_NODE_LIST})) msg = await ws.receive() self.nodes = json.loads(msg.data) await ws.close() # just for check async def response_block_chain(self, request): return web.Response(text=self.chain.json(), content_type="application/json") async def response_node_list(self, request): return web.Response(text=json.dumps(self.nodes, indent=2), content_type="application/json") # blockchain do async def connect_to_peers(self, peers): if self.session == None: self.session = aiohttp.ClientSession() for peer in peers: if peer[0] == self.addr and peer[1] == self.port: continue conn = await self.session.ws_connect( "http://{}:{}/ws".format(*peer)) self.connections.append(conn) async def broadcast(self, msg): for peer in self.connections: await peer.send_str(msg) async def ws_handler(self, request): ws = web.WebSocketResponse() await ws.prepare(request) async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: msg = json.loads(msg.data) if msg["type"] == MessageType.REGISTER_ME: # 새로운 노드 연결 node = msg["nodeinfo"] await self.connect_to_peers([node]) self.nodes.append(node) elif msg["type"] == MessageType.REQUEST_NODE_LIST: # 노드 목록 알려줌 await ws.send_json(self.nodes) elif msg["type"] == MessageType.REQUEST_MAKE_BLOCK: # 블록 생성함 await asyncio.sleep(random.randint(3, 10)) # 해시 푸는 속도라고 가정하자 tr_info = msg["data"] _lastblock = self.chain.get_latest_block() new_block = Block(_lastblock.index + 1, tr_info["data"], tr_info["timestamp"], _lastblock.hash, '') new_block.calculate() if new_block.index > self.chain.latest_block.index: self.chain.add_block(new_block) # 컨펌 받기 await self.broadcast( json.dumps({ "type": MessageType.REQUEST_CONFIRM_BLOCK, "chain": self.chain.json() })) await ws.send_str("[+] Well done !") elif msg["type"] == MessageType.REQUEST_CONFIRM_BLOCK: # 블록 생성 컨펌해줌 blocks = [ Block.from_dict(j) for j in json.loads(msg["chain"]) ] if len(blocks) > self.chain.length: if BlockChain.is_valid_chain(blocks): self.chain.blocks = blocks else: pass elif msg.type == aiohttp.WSMsgType.Error: print('ws connection closed with exception ', ws.exception()) return ws
from block import Block from blockchain import BlockChain if __name__ == '__main__': block_chain = BlockChain() block_chain.add_block("第一个交易是转账10块") block_chain.add_block("第二个交易是转账20") block_chain.print_chain()
class Scrooge(): """ Class representing the maintainer Scrooge who will be monitoring every progress in his network and responsible for creating `Coin`s and verify transactions. This class possesses a private and a public key for its own authentications and """ def __init__(self, users): self.__private_key, self.public_key = gen_keys() self.blockchain = BlockChain() self.users = users self.current_building_block = Block() self.last_block = None self.init() def process_transaction(self, transaction, sender_pubk): verified_check = self.verify_transaction(transaction, sender_pubk) double_spending_check = self.is_double_spending(transaction) if not verified_check: logger('|TRANSACTION REJECTED\t-\tInvalid Transaction|') return if double_spending_check: logger('|TRANSACTION REJECTED\t-\tDouble Spending Detected|\n|From User \t\t\t\t'+str(sender_pubk.__hash__())+'|') return transaction_previous_hash = self.retrieve_transaction_previous_hash(transaction) transaction.add_prev_transaction(transaction_previous_hash) self.add_transaction_to_block(transaction) def retrieve_transaction_previous_hash(self, transaction): previous_hashes = [] for coin in transaction.coins: previous_hash = self.blockchain.retrieve_coin_previous_transaction(coin) if previous_hash != None: previous_hashes.append(previous_hash) if len(previous_hashes) == 0: previous_hashes = None elif len(previous_hashes) <= 1: previous_hashes = previous_hashes[0] return previous_hashes def create_coins(self, amount, user_id): return [Coin(user_id) for _ in range(amount)] def init(self): self.log_users() # self.last_transaction = None for user in self.users: user_id = user.id coins = self.create_coins(10, 'scrooge') transaction = Transaction(self.public_key, coins, user_id, genre="create") if self.__sign(transaction): self.process_transaction(transaction, self.public_key) def log_users(self): logger('='*64+'\nUsers Report:\n'+'='*64) string_users = '' for user in self.users: string_users += user.to_string(self) logger(string_users+'\n'+'='*64) def add_coin_to_user(self, transaction): receiver_pubk = transaction.receiver transaction_coins = transaction.coins for user in self.users: if user.id == receiver_pubk: user.add_transaction(transaction_coins) break def add_transaction_to_block(self, transaction): if not self.current_building_block.add_transaction(transaction): self.last_block = self.current_building_block self.publish_block(self.current_building_block) def publish_block(self, block): self.blockchain.add_block(block) self.current_building_block = Block(transactions=[], hash_prev_block=self.last_block.id) for transaction in block.transactions: self.add_coin_to_user(transaction) self.log_users() def verify_transaction(self, transaction, sender_pk): return verify(sender_pk, transaction.signature, transaction.hash_val) def is_double_spending(self, transaction): return self.current_building_block.is_double_spending(transaction) def sign_last_block(self): self.__sign(self.current_building_block) def __sign(self, obj): if(isinstance(obj, Transaction)): try: transaction_content = get_hash(obj) signature = sign(self.__private_key, transaction_content) obj.add_signing(signature) obj.add_hash(transaction_content) return True except: return False else: try: block_content = get_hash(obj) signature = sign(self.__private_key, block_content) obj.add_signing(signature) return True except: return False
class Node(object): def __init__(self): self.chain = BlockChain() # 初始情况,默认先查看本地文件 self.neighbors = set() # 邻接点 self.transactions = [] # 交易的集合 self.new_block = None # 新的区块,用于挖矿 self.pk, self.sk = self.get_key() # 产生结点的公钥和私钥 self.port = None self.add_neighbors() # 初始化邻居节点 def add_neighbors(self): """ 添加邻居结点 :return:<None> """ for peers in PEERS: if self.port == str(peers).split(':')[2]: # 不能添加自己的地址 continue self.neighbors.add(peers) @staticmethod def get_key(): """ 获取公钥和私钥,注意字符串和byte之间的转化 :return: <pk,sk> """ pk = None sk = None if not os.path.exists('/node_key.json'): # 不存在就新建 with open('node_key.json', 'w') as json_file: sk = SigningKey.generate(curve=NIST384p) pk = sk.get_verifying_key() msg = {"pk": str(pk), "sk": str(sk.to_string())} json_file.write(json.dumps(msg, sort_keys=True)) else: with open('node_key.json') as json_file: # 存在直接读取 msg = json_file.read() pk = msg['pk'].encode("utf8") # 转化成bytes sk1 = msg['vk'].encode() sk = SigningKey.from_string(sk1, curve=NIST384p) return pk, sk def add_new_neighbor(self, address): """ 添加新的邻居结点 :param address: url地址 :return: <None> """ parsed_url = urlparse(address) if parsed_url.netloc or parsed_url.path: self.neighbors.add(address) else: raise ValueError('Invalid URL') def broadcast_transaction(self, transaction): """ 向邻接结点广播新的交易 :return: <None> """ for url in self.neighbors: try: requests.get(url=url + "/", timeout=0.2) # 0.2秒的延迟等待,否则就当做掉线处理 requests.post(url=url + "/receive_transaction", data=json.dump(transaction, sort_keys=True)) except: self.neighbors.remove(url) # 删除掉线的结点 print("node" + url + " not online !") def broadcast_new_block(self, block): """ 向其它结点广播挖出的区块 :param block: 新的区块 :return: <None> """ for url in self.neighbors: try: requests.get(url=url + "/", timeout=0.2) # 0.2秒的延迟等待,否则就当做掉线处理 requests.post(url=url + "/get_mined_block", data=json.dump(block, sort_keys=True)) return True except: self.neighbors.remove(url) # 删除掉线的结点 print("node" + url + " not online !") return False def add_new_transaction(self, transaction): """ 根据签名合法性添加新的交易 :return: <bool> """ pk_string = str(transaction['sender']) signature = transaction['signature'] message = json.dump(transaction['message'], sort_keys=True) # 签名正确,而且不是重复的交易 if is_valid_transaction( pk_string, message, signature) and transaction not in self.transactions: self.broadcast_transaction(transaction) self.transactions.append(transaction) return True return False def add_new_block(self, block): """ 添加新的区块,为了验证其它区块挖矿的合理性 :param block: block :return: <bool> """ if proof_of_work(self.chain.last_block, block): # 处理交易,并且添加新的区块 self.chain.last_block.transaction.append(self.transactions) self.transactions.clear() self.chain.add_block(block) return True return False def get_new_chain(self): """ 对于新上线的结点,需要获得最长的有效的区块链 :return: <None> """ for url in self.neighbors: try: reponse = requests.get(url=url + "/chain", timeout=0.2) # 获取区块链的数据 except: self.neighbors.remove(url) # 删除掉线的结点 print("node" + url + " not online !") continue # length = reponse['length'] chain = reponse['chain'] # 最长的有效区块链 self.chain.resolve_conflicts(chain) def mine(self): """ 产生新的区块,相当于挖矿 :return: 新的区块 """ # 挖矿之前,需要先和其它结点达成共识 self.get_new_chain() nonce = 0 last_block = self.chain[-1] while not proof_of_work(last_block, nonce): nonce += 1 message = { "receiver": self.pk, # 发给自己 "amount": 1, # 奖励的数目 "data": "a new block", # 一些其他的信息 } transaction = { "sender": "0", # 发送者为0 "signature": "0", # 签名为0 "message": message # 自定义的消息 } msg = { "index": len(self.chain.blocks), "time_stamp": time(), "previous_hash": last_block.current_hash, "nonce": nonce, "data": "", "transaction": transaction } # 挖出新的区块后,需要把交易追加到最后一个区块中,同时清空交易缓存 last_block = self.chain.last_block last_block.transactions.append(self.transactions) transaction.clear() # 追加新的区块 block = Block(msg) self.chain.add_block(block) return block
def mine_block(): chain = BlockChain() block = mine(chain.get_last_block()) print block.__dict__ if chain.add_block(block): chain.broadcast(block)
# print (block) # print (block.hash_is_valid(block.hash())) # print (block.hash(1)) # print (block.hash_is_valid(block.hash(1))) # # Script 2 : Mining # block = Block(data='Transaction 100 catcoins from Alice to Bob') # block.mine() # print(block) # # Script 3 : Generate block chain chain = BlockChain() print(chain) block = Block(data="Txn 100 catcoins from Alice to Bob") chain.add_block(block) print(chain) # # Script 4 : Chaining ts = time.time() for i in range(6): new_block = Block(i) new_block.mine() chain.add_block(new_block) print("====") print("Total Duration: {0:.2f} seconds".format(time.time() - ts)) chain.print()