def handle_sendblock(self, payload): new_block = payload with self.server.node_manager.lock: blockchain = self.server.node_manager.blockchain block_height = db.get_block_height(blockchain.wallet.address) latest_block = db.get_block_data_by_index( blockchain.get_wallet_address(), block_height - 1) if (latest_block.current_hash == new_block.previous_hash) and (latest_block.index + 1 == new_block.index): # 校验交易是否有效 is_valid = True for idx in range(len(new_block.transactions)): tx = new_block.transactions[-1 - idx] if not blockchain.verify_transaction(tx): is_valid = False break if is_valid: db.write_to_db(blockchain.wallet.address, new_block) # 重新挖矿 blockchain.current_transactions = [] db.clear_unconfirmed_tx_from_disk( blockchain.wallet.address) else: self.add_to_candidate_blocks(blockchain, new_block) blockchain.set_consensus_chain()
def node_info(): values = request.get_json() required = ['ip', 'port'] if not all(k in values for k in required): return 'Missing values', 400 ip = values['ip'] port = values['port'] block_height = db.get_block_height(blockchain.wallet.address) latest_block = db.get_block_data_by_index(blockchain.wallet.address, block_height - 1) block_hash = latest_block.current_hash timestamp = latest_block.timestamp time_local = time.localtime(timestamp) response = { 'address': ip + ':' + str(port), 'block_height': block_height, 'block_hash': block_hash, 'wallet_address': blockchain.wallet.address, # 'balance': blockchain.get_balance(blockchain.wallet.address), 'timestamp': time.strftime("%Y-%m-%d %H:%M:%S", time_local) } return jsonify(response), 200
def set_consensus_chain(self): # 通过POW机制选取nonce最大的链作为公共链 for block_index in list(self.candidate_blocks.keys()): if block_index <= db.get_block_height( self.get_wallet_address()) - 1: curr_block = db.get_block_data_by_index( self.get_wallet_address(), block_index) max_nonce_block = curr_block for candidate_block in self.candidate_blocks[block_index]: if (candidate_block.previous_hash == curr_block.previous_hash) and ( candidate_block.nonce > max_nonce_block.nonce): max_nonce_block = candidate_block # 校验每一笔交易 valid_flag = True for idx in range(len(max_nonce_block.transactions)): tx = max_nonce_block.transactions[-1 - idx] if not self.verify_transaction(tx): valid_flag = False if valid_flag and max_nonce_block.current_hash != curr_block.current_hash: print('[Info] consensusing, replace with new block', max_nonce_block.current_hash) db.write_to_db(self.get_wallet_address(), max_nonce_block)
def tx_info_app(): block_index = int(request.args.get('block_index')) txid = request.args.get('txid') block = db.get_block_data_by_index(blockchain.wallet.address, block_index) for tx in block.transactions: if tx.txid == txid: return json.dumps(tx.json_output()), 200 return 'not exist!', 200
def block_info(): height = request.args.get('height') block_index = int(height) - 1 block = db.get_block_data_by_index(blockchain.wallet.address, block_index) json_transaction = list() for tx in block.transactions: txins = tx.txins txouts = tx.txouts from_addr = list() to_addr = list() amount = 0 for txin in txins: if txin.prev_tx_out_idx != -1: address = Wallet.get_address(txin.pubkey) if address not in from_addr: from_addr.append(address) for txout in txouts: value = txout.value script_pub_key = txout.scriptPubKey if len(script_pub_key) == 5: recv_addr = get_address_from_ripemd160(script_pub_key[2]) to_addr.append({'receiver': recv_addr, 'value': value}) new_tx = { 'txid': tx.txid, 'senders': from_addr, 'receivers': to_addr, 'amount': amount, 'timestamp': tx.timestamp } json_transaction.append(new_tx) response = { 'index': block.index, 'current_hash': block.current_hash, 'previous_hash': block.previous_hash, 'timestamp': block.timestamp, 'merkleroot': block.merkleroot, 'difficulty': block.difficulty, 'nonce': block.nonce, 'transactions': json_transaction } return jsonify(response), 200
def tx_in_block(): values = request.get_json() block_index = int(request.args.get('block_index')) block = db.get_block_data_by_index(blockchain.wallet.address, block_index) tmp = dict() cnt = 0 for tx in block.transactions: tmp[str(cnt)] = { 'txid': tx.txid, 'timestamp': time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(tx.timestamp)), 'vid': tx.vid } cnt += 1 return json.dumps(tmp), 200
def find_transaction(self, txid): """ 通过交易id找到一笔Tx交易 :param txid: <str>交易id :return: """ # 在区块中寻找(已确认的交易) block_height = db.get_block_height(self.wallet.address) for index in range(block_height): block = db.get_block_data_by_index(self.wallet.address, index) # 1.获取区块下的所有的交易 transactions = block.get_transactions() for tx in transactions: if tx.txid == txid: return tx # 在交易池中寻找(未确认的交易)TODO待确认 for k in range(len(self.current_transactions)): uncomfirmed_tx = self.current_transactions[-1 - k] if uncomfirmed_tx.txid == txid: return uncomfirmed_tx return None
def get_last_block(self): block_height = db.get_block_height(self.wallet.address) return db.get_block_data_by_index(self.wallet.address, block_height - 1)
def find_spendalbe_outputs(self, from_addr): """ 获取from_addr可以用于交易的TxOutput(未使用过的), :param from_addr: <str>发送方钱包地址 :return: """ unspent_txout_list = list() spent_txout_list = list() balance = 0 # Step0:遍历交易池中已经发生过的交易(未打包进区块,未确认) # 备注:要从最新的交易开始遍历!!!!! for i in range(len(self.current_transactions)): unconfirmed_tx = self.current_transactions[ len(self.current_transactions) - 1 - i] txid = unconfirmed_tx.txid # 遍历当前交易下所有的TxInput if not unconfirmed_tx.is_coinbase(): # print 'txid:', txid # 记录当前tx下被from_addr被使用过的上一次交易的输出,即记录txid和out_idx for txin in unconfirmed_tx.txins: if txin.can_unlock_txoutput_with(from_addr): spent_txid = txin.prev_txid spent_tx_out_idx = txin.prev_tx_out_idx spent_txout_list.append((spent_txid, spent_tx_out_idx)) # 遍历交易下所有的未使用过的TxOutput for out_idx in range(len(unconfirmed_tx.txouts)): txout = unconfirmed_tx.txouts[out_idx] if not (txid, out_idx) in spent_txout_list: if txout.can_be_unlocked_with(from_addr): unspent_txout_list.append((txid, out_idx, txout)) # -------------------------------------------------- # Step1:获取from_addr下可以未使用过的TxOutput(打包在区块,已确认) block_height = db.get_block_height(self.wallet.address) for i in range(block_height): block = db.get_block_data_by_index(self.wallet.address, block_height - 1 - i) # 1.获取区块下的所有的交易 transactions = block.get_transactions() # 备注:要从最新的交易开始遍历!!!!! for k in range(len(transactions)): tx = transactions[len(transactions) - 1 - k] if not self.verify_transaction(tx): # 校验交易是否有效 print('[Info] invalid tx', tx.txid, 'block index:', i) continue txid = tx.txid # 当前交易的id # 2.遍历某个交易下所有的TxInput if not tx.is_coinbase(): # 记录当前tx下被from_addr被使用过的上一次交易的输出,即记录txid和out_idx for txin in tx.txins: if txin.can_unlock_txoutput_with(from_addr): spent_txid = txin.prev_txid spent_tx_out_idx = txin.prev_tx_out_idx spent_txout_list.append( (spent_txid, spent_tx_out_idx)) # 3.遍历某个交易下所有的未使用过的TxOutput for out_idx in range(len(tx.txouts)): txout = tx.txouts[out_idx] if not (txid, out_idx) in spent_txout_list: if txout.can_be_unlocked_with(from_addr): unspent_txout_list.append((txid, out_idx, txout)) # Step2:计算这些未使用过的TxOutput输出之和 for txid, out_idx, txout in unspent_txout_list: balance += txout.value return balance, unspent_txout_list
def get_balance_by_db(self, from_addr): """ 获取from_addr可以用于交易的TxOutput(未使用过的),读取交易池和区块链的本地副本,避免被加锁 :param from_addr: <str>发送方钱包地址 :return: <int> """ unspent_txout_list = list() spent_txout_list = list() balance = 0 # Step1:遍历交易池中已经发生过的交易(未打包进区块,未确认) # 备注:要从最新的交易开始遍历!!!!! current_transactions = db.get_all_unconfirmed_tx(self.wallet.address) current_transactions = sorted(current_transactions, key=lambda x: x.timestamp, reverse=False) for i in range(len(current_transactions)): unconfirmed_tx = current_transactions[len(current_transactions) - 1 - i] txid = unconfirmed_tx.txid # 遍历当前交易下所有的TxInput if not unconfirmed_tx.is_coinbase(): # print 'txid:', txid # 记录当前tx下被from_addr被使用过的上一次交易的输出,即记录txid和out_idx for txin in unconfirmed_tx.txins: if txin.can_unlock_txoutput_with(from_addr): spent_txid = txin.prev_txid spent_tx_out_idx = txin.prev_tx_out_idx spent_txout_list.append((spent_txid, spent_tx_out_idx)) # 遍历交易下所有的未使用过的TxOutput for out_idx in range(len(unconfirmed_tx.txouts)): txout = unconfirmed_tx.txouts[out_idx] if not (txid, out_idx) in spent_txout_list: if txout.can_be_unlocked_with(from_addr): unspent_txout_list.append((txid, out_idx, txout)) # -------------------------------------------------- # Step2:获取from_addr下可以未使用过的TxOutput(打包在区块,已确认) block_height = db.get_block_height(self.wallet.address) for i in range(block_height): block = db.get_block_data_by_index(self.wallet.address, block_height - 1 - i) # 1.获取区块下的所有的交易 transactions = block.get_transactions() # 备注:要从最新的交易开始遍历!!!!! for k in range(len(transactions)): tx = transactions[len(transactions) - 1 - k] if not self.verify_transaction(tx): # 校验交易是否有效 continue txid = tx.txid # 当前交易的id # 2.遍历某个交易下所有的TxInput if not tx.is_coinbase(): # 记录当前tx下被from_addr被使用过的上一次交易的输出,即记录txid和out_idx for txin in tx.txins: if txin.can_unlock_txoutput_with(from_addr): spent_txid = txin.prev_txid spent_tx_out_idx = txin.prev_tx_out_idx spent_txout_list.append( (spent_txid, spent_tx_out_idx)) # 3.遍历某个交易下所有的未使用过的TxOutput for out_idx in range(len(tx.txouts)): txout = tx.txouts[out_idx] if not (txid, out_idx) in spent_txout_list: if txout.can_be_unlocked_with(from_addr): unspent_txout_list.append((txid, out_idx, txout)) # Step2:计算这些未使用过的TxOutput输出之和 for txid, out_idx, txout in unspent_txout_list: balance += txout.value return balance
def block_info(): block_index = request.args.get('block_index') block = db.get_block_data_by_index(blockchain.wallet.address, block_index) json_transaction = list() for tx in block.transactions: if isinstance(tx, Tx_vid): new_tx = { 'txid': tx.txid, 'timestamp': tx.timestamp, 'type': 'vid', 'vid': tx.vid } elif isinstance(tx, Tx_report): new_tx = { 'txid': tx.txid, 'timestamp': tx.timestamp, 'type': 'report', 'edgeId': tx.edgeId, 'meanSpeed': tx.meanSpeed, 'vehicleNum': tx.vehicleNum } elif isinstance(tx, Tx_easy): new_tx = { 'txid': tx.txid, 'sender': tx.sender, 'receiver': tx.receiver, 'amount': tx.amount, 'timestamp': tx.timestamp } elif isinstance(tx, Transaction): txins = tx.txins txouts = tx.txouts from_addr = list() to_addr = list() amount = 0 for txin in txins: if txin.prev_tx_out_idx != -1: address = Wallet.get_address(txin.pubkey) if address not in from_addr: from_addr.append(address) for txout in txouts: value = txout.value script_pub_key = txout.scriptPubKey if len(script_pub_key) == 5: recv_addr = get_address_from_ripemd160(script_pub_key[2]) to_addr.append({'receiver': recv_addr, 'value': value}) new_tx = { 'txid': tx.txid, 'senders': from_addr, 'receivers': to_addr, 'amount': amount, 'timestamp': tx.timestamp } json_transaction.append(new_tx) response = { 'index': block.index, 'timestamp': block.timestamp, 'current_hash': block.current_hash, 'previous_hash': block.previous_hash, 'merkleroot': block.merkleroot, 'transactions': json_transaction } return jsonify(response), 200
def tx_in_block(): values = request.get_json() block_index = int(request.args.get('block_index')) block = db.get_block_data_by_index(blockchain.wallet.address, block_index) tmp = dict() cnt = 0 for tx in block.transactions: if isinstance(tx, Tx_vid): tmp[str(cnt)] = { 'txid': tx.txid, 'timestamp': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(tx.timestamp)), 'type': 'vid', 'vid': tx.vid } cnt += 1 elif isinstance(tx, Tx_report): tmp[str(cnt)] = { 'txid': tx.txid, 'timestamp': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(tx.timestamp)), 'type': 'report', 'edgeId': tx.edgeId, 'meanSpeed': tx.meanSpeed, 'vehicleNum': tx.vehicleNum } cnt += 1 elif isinstance(tx, Tx_easy): tmp[str(cnt)] = { 'txid': tx.txid, 'sender': tx.sender, 'receiver': tx.receiver, 'amount': tx.amount, 'timestamp': tx.timestamp } cnt += 1 elif isinstance(tx, Transaction): txins = tx.txins txouts = tx.txouts from_addr = list() to_addr = list() amount = 0 for txin in txins: if txin.prev_tx_out_idx != -1: address = Wallet.get_address(txin.pubkey) if address not in from_addr: from_addr.append(address) for txout in txouts: value = txout.value script_pub_key = txout.scriptPubKey if len(script_pub_key) == 5: recv_addr = get_address_from_ripemd160(script_pub_key[2]) to_addr.append({'receiver': recv_addr, 'value': value}) tmp[str(cnt)] = { 'txid': tx.txid, 'senders': from_addr, 'receivers': to_addr, 'amount': amount, 'timestamp': tx.timestamp } cnt += 1 return json.dumps(tmp), 200