Пример #1
0
    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)
Пример #2
0
    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()
Пример #3
0
    def bootstrap(self, seed_nodes=[]):
        """
        根据初始节点引导初始化
        :param seed_nodes:<Node list> 种子节点列表
        :return:
        """

        for seed_node in seed_nodes:
            #判断是否已经存在在邻居中

            flag = self.tablsp.judnei(seed_node)  #不同的格式怎么处理todo
            print self.tablsp.basetable[1]
            if flag == 0:  #不在邻居中
                #将该节点放入邻居中
                self.tablsp.neighbourip.append(seed_node.ip)
                self.tablsp.neighbourport.append(seed_node.port)
                #设置距离
                d = random.choice((1, 2, 3, 4, 40, 40, 40, 40))
                print "insert distance in bootrs"
                print d
                self.tablsp.neighbourdistance.append(d)
                # 握手,加入lsptab中
                self.sendversion(
                    seed_node,
                    Version(
                        1, int(time.time()), self.node_id, seed_node.node_id,
                        db.get_block_height(
                            self.blockchain.get_wallet_address()), d))
#建立邻居完毕后整理lsp
        self.tablsp.generatelsp()
        print "neighbour"
        print self.tablsp.lsp
Пример #4
0
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
Пример #5
0
    def handle_verack(self, payload):
        version = payload.version
        if version != 1:
            # 版本不一样,拒绝
            print '[Warn] invalid version, ignore!!'
            pass
        else:
            client_node_id = payload.from_id
            client_ip, client_port = self.client_address
            new_node = Node(client_ip, client_port, client_node_id)
            new_node.version = 1
            self.server.node_manager.buckets.insert(new_node)
            blockchain = self.server.node_manager.blockchain

            if payload.best_height > db.get_block_height(
                    blockchain.get_wallet_address()):
                # TODO 检查best_height,同步区块链
                pass
Пример #6
0
    def bootstrap(self, seed_nodes=[]):
        """
        根据初始节点引导初始化
        :param seed_nodes:<Node list> 种子节点列表
        :return:
        """
        for seed_node in seed_nodes:
            # 握手
            self.sendversion(
                seed_node,
                Version(
                    1, int(time.time()), self.node_id, seed_node.node_id,
                    db.get_block_height(self.blockchain.get_wallet_address())))

        for seed_node in seed_nodes:
            self.iterative_find_nodes(self.client.node_id, seed_node)

        if len(seed_nodes) == 0:
            for seed_node in self.buckets.get_all_nodes():
                self.iterative_find_nodes(self.client.node_id, seed_node)
Пример #7
0
    def handle_version(self, payload):
        version = payload.version
        if version != 1:
            # 版本不一样,拒绝
            print '[Warn] invalid version, ignore!!'
            pass
        else:
            client_ip, client_port = self.client_address
            client_node_id = payload.from_id
            new_node = Node(client_ip, client_port, client_node_id)
            new_node.version = 1
            self.server.node_manager.buckets.insert(new_node)
            blockchain = self.server.node_manager.blockchain

            block_counts = db.get_block_height(blockchain.get_wallet_address())
            verack = Verack(1, int(time.time()),
                            self.server.node_manager.node_id, client_node_id,
                            block_counts)
            self.server.node_manager.sendverck(new_node, verack)

            if payload.best_height > block_counts:
                # TODO 检查best_height,同步区块链
                pass
Пример #8
0
    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
Пример #9
0
 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)
Пример #10
0
    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
Пример #11
0
    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
Пример #12
0
def block_height():
    response = {
        'code': 0,
        'value': db.get_block_height(blockchain.wallet.address)
    }
    return json.dumps(response), 200