Esempio n. 1
0
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
Esempio n. 2
0
class Node:
    def __init__(self):
        self.wallet = Wallet()
        # By default the node generate a new wallet while the user
        # can still generate a new WALLET
        self.wallet.create_keys()
        self.blockchain = BlockChain(self.wallet.public_key)
        #self.blockchain = None

    def get_transaction_value(self):
        #tx_sender = input("Enter the sender of the transaction:")
        tx_sender = self.wallet.public_key
        tx_recipient = input("Enter the recipient of the transaction:")
        tx_amount = float(input("Enter the amount of the transaction:"))
        return tx_sender, tx_recipient, tx_amount

    def print_blockchain_elements(self):
        for block in self.blockchain.get_chain():
            print(block)
        else:
            print("-" * 30)

    def get_user_choice(self):
        return int(input("Your choice:"))

    def display_balance_all(self):
        for person in self.blockchain.participants:
            print("Balance of {} : {:6.2f}".format(
                person, self.blockchain.get_balance(person)))

    def listen_for_input(self):
        waiting_for_input = True
        while waiting_for_input:
            print("Please select your choice: ")
            print("1) Add a a new transaction. ")
            print("2) Mine a new block")
            print("3) Print the blockchain. ")
            print("4) Show participants. ")
            print("5) Manipulate. ")
            print("6) Verify. ")
            print("7) Quit. ")
            print("8) Load Data.")
            print("9) Create Wallet")
            print("10) Load Wallet")
            print("11) Save Keys")
            user_choice = self.get_user_choice()
            if user_choice == 1:
                tx_sender, tx_recipient, tx_amount = self.get_transaction_value(
                )
                signature = self.wallet.sign_transaction(
                    tx_sender, tx_recipient, tx_amount)
                if self.blockchain.add_transaction(tx_sender, tx_recipient,
                                                   self.wallet.public_key,
                                                   signature, tx_amount):
                    print("Transaction successfully added.")
                else:
                    print("Transaction failed.")
                print([
                    tx.__dict__
                    for tx in self.blockchain.get_open_transactions()
                ])
            elif user_choice == 2:
                if self.blockchain.mine_block():
                    print(" New Block Mined!")
            elif user_choice == 3:
                self.print_blockchain_elements()
            elif user_choice == 4:
                print(self.blockchain.participants)
            elif user_choice == 5:
                print("NONE")
            elif user_choice == 6:
                print(Verification.verify_chain(self.blockchain.get_chain()))

            elif user_choice == 7:
                waiting_for_input = False

            elif user_choice == 8:
                self.blockchain.load_data()

            elif user_choice == 9:  # Create Wallet
                self.wallet.create_keys()
                self.blockchain = BlockChain(self.wallet.public_key)
                print(self.wallet.public_key)

            elif user_choice == 10:  # Load Wallet
                self.wallet.load_keys()
                self.blockchain = BlockChain(self.wallet.public_key)
                print(self.wallet.public_key)

            elif user_choice == 11:  # Save the keys
                if self.wallet.save_keys():
                    print("Keys SAVED.")
                else:
                    print("Keys NOT saved.")

            else:
                print("Not a valid input.")

            if not Verification.verify_chain(self.blockchain.get_chain()):
                print("Invalid blockchain")
                self.print_blockchain_elements()
                waiting_for_input = False

            self.display_balance_all()

        else:
            print("User left.")
Esempio n. 3
0
class Node:

    def __init__(self):
        self.wallet = Wallet()
        self.wallet.create_keys()
        self.blockchain = BlockChain(self.wallet.public_key)

    def get_transaction_value(self):
        """ Returns the input of the user ( a new transaction amount) as float. """

        tx_recipient = input("Enter the recipient of the transaction: ")
        tx_amount = float(input("Your transaction amount please: "))
        return tx_recipient, tx_amount

    def print_blockchain_element(self):
        """Out the blockchain list in the terminal"""
        for block in self.blockchain.get_chain():
            print("Displaying Block")
            print(block)

    def get_user_choice(self):
        user_input = input('Enter your choice: ')
        return user_input

    def listen_for_input(self):
        waiting_for_input = True
        while waiting_for_input:
            print("Please Choose")
            print("1: Add a new trasaction value")
            print("2: Mine a new block ")
            print("3: Output the blockchain blocks")
            print("4: Check transaction validity")
            print("5: Create wallet")
            print("6: Load wallet")
            print("7: save wallet keys ")
            print("q: Quit")
            user_choice = self.get_user_choice()
            if user_choice == "1":
                tx_data = self.get_transaction_value()
                recipient, amount = tx_data
                signature = self.wallet.sign_transactions(self.wallet.public_key, recipient, amount)
                if self.blockchain.add_transaction(recipient, self.wallet.public_key, amount, signature):
                    print('Added Transaction')
                else:
                    print('Transaction Failed')
                print(self.blockchain.get_open_transactions())

            elif user_choice == "2":
                if not self.blockchain.mine_block():
                    print('Mining failed. Got no wallet')

            elif user_choice == "3":
                self.print_blockchain_element()

            elif user_choice == "4":
                if Verification.verify_transactions(self.blockchain.get_open_transactions(), self.blockchain.get_balance):
                    print("All transactions are valid")
                else:
                    print("There are invalid transactions")
            elif user_choice == "5":
                self.wallet.create_keys()
                self.blockchain = BlockChain(self.wallet.public_key)
            elif user_choice == "6":
                self.wallet.load_keys()
                self.blockchain = BlockChain(self.wallet.public_key)

            elif user_choice == "7":
                if self.wallet.public_key != None and self.wallet.private_key != None:
                    self.wallet.save_keys()
            elif user_choice == "q":
                waiting_for_input = False

            else:
                print("Invalid input. Please select a value from the list")
            if not Verification.verify_chain(self.blockchain.get_chain()):
                print("Invalid blockchain")
                break
            print(
                f'Balance of {self.wallet.public_key}: {self.blockchain.get_balance():6.2f}')
        else:
            print("User left")

        print('Done')
Esempio n. 4
0
class ServerCore:
    def __init__(self,
                 my_port=50082,
                 core_node_host=None,
                 core_node_port=None):
        self.server_state = STATE_INIT
        print('Initializing server...')
        self.my_ip = utils.get_host()
        print('Server IP address is set to ... ', self.my_ip)
        self.my_port = my_port
        self.cm = ConnectionManager(self.my_ip, self.my_port,
                                    self.__handle_message)
        self.core_node_host = core_node_host
        self.core_node_port = core_node_port
        self.miners_wallet = Wallet()
        self.blockchain = BlockChain(self.miners_wallet.blockchain_address)
        self.mining_semaphore = threading.Semaphore(1)
        self.__print_info()

    def __print_info(self):
        print({
            'private_key': self.miners_wallet.private_key,
            'public_key': self.miners_wallet.public_key,
            'blockchain_address': self.miners_wallet.blockchain_address
        })

    def start(self):
        """
            Coreノードとしての待受を開始
        """
        self.server_state = STATE_STANDBY
        self.cm.start()
        self.start_mining()

    def join_network(self):
        """
            事前に取得した情報に従い拠り所となる他のCoreノードに接続
        """
        if self.core_node_host is not None:
            self.server_state = STATE_CONNECTED_TO_NETWORK
            self.cm.join_network(self.core_node_host, self.core_node_port)
        else:
            print('This server is runnning as Genesis Core Node...')

    def shutdown(self):
        """
            待ち受け状態のServer Socketを閉じて終了
        """
        self.server_state = STATE_SHUTTING_DOWN
        print('Shutdown server...')
        self.cm.connection_close()

    def start_mining(self):
        print('start mining')
        is_acquire = self.mining_semaphore.acquire(blocking=False)
        if is_acquire:
            with contextlib.ExitStack() as stack:
                stack.callback(self.mining_semaphore.release)
                self.__mining()
                mining_interval = self.blockchain.mining_speed + random.uniform(
                    9.8, 10.3)
                loop = threading.Timer(round(mining_interval),
                                       self.start_mining)
                loop.start()

    def __mining(self):
        start = time.time()
        self.blockchain.add_transaction(
            sender_blockchain_address=MINING_SENDER,
            recipient_blockchain_address=self.blockchain.blockchain_address,
            value=MINING_REWARD)
        nonce = self.blockchain.proof_of_work()
        if nonce == -1:
            return False
        previous_hash = self.blockchain.hash(self.blockchain.chain[-1])
        is_created, block = self.blockchain.create_block(nonce, previous_hash)
        if not is_created:
            return False
        self.delete_transaction_for_all_peer()

        print({'action': 'mining', 'status': 'success'})
        utils.pprint(self.blockchain.chain)

        self.send_all_chain_for_consensus()

        elapse = round(time.time() - start, 4)
        self.blockchain.difficulty_adjustment(elapse)

        # print('mining speed : ', str(round(self.mining_speed, 3)))
        # print('difficult : ', str(self.difficulty))

        return True

    def delete_transaction_for_all_peer(self):
        """
            ノードのトランザクションプールをからにするメッセージの送信
        """
        new_message = self.cm.get_message_text(MSG_DELETE_TRANSACTION)
        self.cm.send_msg_to_all_peer(new_message)

    def send_all_chain_for_consensus(self):
        """
            チェーンを全てのノードに送信してコンセンサス
        """
        my_chain = self.blockchain.chain
        chain_data = json.dumps(my_chain)
        new_message = self.cm.get_message_text(RSP_FULL_CHAIN, chain_data)
        self.cm.send_msg_to_all_peer(new_message)

    def __handle_message(self, msg, is_core, peer=None):
        """
            ConnectionManagerに引き渡すコールバックの中身。
        """
        print('message_type : ', msg[2])
        if peer is not None:
            if msg[2] == MSG_REQUEST_FULL_CHAIN:
                # walletのチェーンを同期
                print('Send our latest blockchain for reply to : ', peer)
                my_chain = self.blockchain.chain
                chain_data = json.dumps(my_chain)
                new_message = self.cm.get_message_text(RSP_FULL_CHAIN,
                                                       chain_data)
                self.cm.send_msg(peer, new_message)
            elif msg[2] == MSG_REQUEST_KEY_INFO:
                # walletにminerの鍵情報を渡す
                key_info = pickle.dumps(self.miners_wallet, 0).decode()
                m_type = MSG_KEY_INFO
                message = self.cm.get_message_text(m_type, key_info)
                self.cm.send_msg(peer, message)
            elif msg[2] == MSG_DELETE_TRANSACTION:
                # transaction poolを空に
                print('DELETE_TRANSACTION is called')
                self.blockchain.transaction_pool = []
        else:
            if msg[2] == MSG_NEW_TRANSACTION:
                print('NEW_TRANSACTION command is called')
                payload = json.loads(msg[4])
                new_transaction = utils.sorted_dict_by_key({
                    'sender_blockchain_address':
                    payload['sender_blockchain_address'],
                    'recipient_blockchain_address':
                    payload['recipient_blockchain_address'],
                    'value':
                    float(payload['value'])
                })
                current_transactions = self.blockchain.transaction_pool.copy()
                print('new transaction : ', new_transaction)
                if new_transaction in current_transactions:
                    print('transaction is already in pool')
                    return
                else:
                    signature = pickle.loads(
                        payload['signature'].encode('utf8'))
                    print('signature', signature)
                    is_transacted = self.blockchain.add_transaction(
                        payload['sender_blockchain_address'],
                        payload['recipient_blockchain_address'],
                        payload['value'], payload['sender_public_key'],
                        signature)
                    if is_transacted:
                        print('new transaction is generated')
                        print('\n\ntransaction_pool',
                              self.blockchain.transaction_pool)
                    if not is_core:
                        # ウォレットからのトランザクションはブロードキャスト
                        print('transaction bloadcasted')
                        m_type = MSG_NEW_TRANSACTION
                        new_message = self.cm.get_message_text(m_type, msg[4])
                        self.cm.send_msg_to_all_peer(new_message)
            elif msg[2] == RSP_FULL_CHAIN:
                print('RSP_FULL_CHAIN command is called')
                if not is_core:
                    return

                new_block_chain = json.loads(msg[4])
                self.blockchain.resolve_conflicts(new_block_chain)