Browse Source

original peer file

xjh 6 years ago
parent
commit
5a5bba1988
1 changed files with 884 additions and 0 deletions
  1. 884 0
      SEECBC-Test/peer.py

+ 884 - 0
SEECBC-Test/peer.py

@@ -0,0 +1,884 @@
+# -*- coding: utf-8 -*-
+
+import random
+from .ecc import VerifyingKey,build_message,convert_pubkey_to_addr
+from .datatype import Pointer,Vin,Vout,UTXO,Tx,Block,get_merkle_root_of_txs
+from .params import Params
+from .consensus import mine,caculate_target
+from .logger import logger
+from .wallet import Wallet
+from .vm import LittleMachine
+from .merkletree import MerkleTree
+
+class Peer(object):
+    
+    def __init__(self,coords = None):
+        self.coords = coords
+        self.network = None
+        self.txs = []
+        self.candidate_block_txs = []
+        self.candidate_block = None
+        self.blockchain = []
+        self.orphan_block = []
+        self.utxo_set = {}
+        self.mem_pool = {}
+        self.orphan_pool = {}
+        self.pid = None
+        self.fee = Params.FIX_FEE_PER_TX
+        self.tx_choice_method = 'whole'
+        self.current_tx = None
+        self.allow_utxo_from_pool = True
+        self.machine = LittleMachine()
+        self._is_wallet_generated = False
+        self.generate_wallet()
+        
+        self._is_block_candidate_created = False
+        self._is_current_tx_created = False
+        self._is_current_tx_sent = False
+        self._delayed_tx = None
+        self._delayed_block = None
+        self._utxos_from_vins = None
+        self._pointers_from_vouts = None
+        self._utxos_from_vouts = None
+        self._txs_removed = None
+        
+        
+        
+    
+    
+    ############################################################
+    # peer as wallet
+    ############################################################
+    """
+    Generate wallet
+    """
+    
+    def generate_wallet(self):
+        if not self._is_wallet_generated:
+            self.wallet = Wallet()
+            self._is_wallet_generated = True
+
+
+    @property
+    def sk(self):
+        return self.wallet.keys[-1].sk.to_bytes() if self.wallet.keys else None
+
+    @property
+    def pk(self):
+        return self.wallet.keys[-1].pk.to_bytes() if self.wallet.keys else None
+
+
+    @property
+    def addr(self):
+        return self.wallet.addrs[-1] if self.wallet.addrs else None
+
+    @property
+    def key_base_len(self):
+        return len(self.sk)
+        
+    """
+    your bank balance
+    """
+    def get_balance(self):
+        utxos = self.get_utxo()
+        return sum(utxo.vout.value for utxo in utxos)
+    
+    """
+    your output
+    """
+    
+    def get_utxo(self):
+        return [utxo for utxo in self.utxo_set.values()
+                if (utxo.vout.to_addr in self.wallet.addrs) and utxo.unspent]
+        
+    def get_unconfirmed_utxo(self):
+        utxos = self.get_utxo()
+        return [utxo for utxo in utxos if not utxo.confirmed]
+    
+    def get_confirmed_utxo(self):
+        utxos = self.get_utxo()
+        return [utxo for utxo in utxos if utxo.confirmed]
+    
+    def set_fee(self,value):
+        self.fee = value
+    
+    def get_fee(self):
+        return self.fee
+
+    def calculate_fees(self,txs=[]):
+        return sum(tx.fee for tx in txs)
+
+    
+    def get_block_reward(self):
+        return Params.FIX_BLOCK_REWARD
+
+
+    """
+    create a transaction 
+    """
+    def create_transaction(self,to_addr,
+                           value,
+                           tx_type = "normal"):
+        
+        if tx_type == 'normal':
+            outputs = create_normal_tx(self,to_addr,value)
+            if outputs:
+                tx_in,tx_out,fee = outputs
+                self.current_tx = Tx(tx_in,tx_out,fee = fee,nlocktime = 0)
+                self.txs.append(self.current_tx)   
+                self._is_current_tx_created = True
+                
+                logger.info('{0}(pid={1}) created a transaction'.format(self,self.pid))
+                return True
+            return False
+        
+
+    """
+    if this is a recorder peer, build rewards for self after won
+    """
+    def create_coinbase(self,value):
+        return Tx.create_coinbase(self.wallet.addrs[-1],value = value)
+    
+    
+    
+    ############################################################
+    # peer as route
+    ############################################################
+    """
+    broadcast a transaction 
+    """
+    def send_transaction(self):
+        if not self.txs:
+            return False
+        
+        if self._is_current_tx_created:
+            sign_utxo_from_tx(self.utxo_set,self.current_tx)
+            
+            add_tx_to_mem_pool(self,self.current_tx) 
+            self._is_current_tx_created = False
+            self._is_current_tx_sent = True
+            
+            logger.info("{0}(pid={1}) sent a transaction to network".format(self,self.pid))
+            return True
+        return False
+    
+    
+    def recieve_transaction(self,tx):
+        if tx and (tx not in self.mem_pool):
+            if self.verify_transaction(tx,self.mem_pool): 
+                add_tx_to_mem_pool(self,tx)
+                return True
+        
+        return False
+
+            
+    def broadcast_transaction(self,tx = None): 
+        if not self._is_current_tx_sent:
+            self.send_transaction()
+        
+        self._is_current_tx_created = False
+        self._is_current_tx_sent = False
+        
+        tx = tx or self.current_tx
+        if tx:
+            peers = self.network.peers[:]
+            peers.remove(self)
+            number = broadcast_tx(peers,tx)
+            self.current_tx = None
+            
+            logger.info("{0}(pid={1})'s transaction verified by {2} peers".format(self,self.pid,number))
+            return number
+        return 0
+    
+        
+    """
+    broadcast a transaction 
+    """ 
+    def broadcast_block(self,block):
+        peers = self.network.peers[:]
+        peers.remove(self)
+        number = broadcast_winner_block(peers,block)
+        logger.info('{0} received by {1} peers'.format(block,number))
+                
+                
+    def locate_block(self,block_hash):
+       return locate_block_by_hash(self,block_hash)
+   
+    
+    def recieve_block(self,block):
+        if not self.verify_block(block):
+            return False
+        return try_to_add_block(self,block)
+    
+    
+    """
+    verify a transaction
+    """
+    
+    def verify_transaction(self,tx,pool = {}):
+        if tx in self.txs:
+            return True
+        return verify_tx(self,tx,pool)
+
+    """
+    verify a block
+    """ 
+    
+    def verify_block(self,block):
+        if self._delayed_tx:
+            fill_mem_pool(self)
+            
+        if self.orphan_pool:
+            check_orphan_tx_from_pool(self)
+            
+        if block == self.candidate_block:
+            return True
+        
+        if not verify_winner_block(self,block):
+            return False
+
+        return True
+    
+    def response_path(self,tx):
+        if tx.id in self.mem_pool:
+            return "unconfirmed"
+
+        tot_height = self.get_height()
+        for i in range(tot_height):
+            txs = self.blockchain[-i-1].txs
+            if tx in txs:
+                break
+            else:
+                return False
+
+        height = tot_height - i
+        idx = txs.index(tx)
+        idxs = [tx.id for tx in txs]
+        merkle = MerkleTree(idxs)
+        path = merkle.get_path(idx)
+        return height,path
+            
+
+        
+    """
+    peer links to p2p network
+    """
+    
+    def login(self):
+        assert self in self.network.off_peers,(
+                "This peer does not connect to network or online"
+                )
+        repeat_log_in(self,self.network)
+        self.update_blockchain()
+        
+                
+    """
+    peer logs out 
+    """
+    def logout(self):
+        assert self in self.network.peers,(
+                "This peer does not connect to network"
+                )
+        log_out(self,self.network)
+    
+    
+    
+    def update_blockchain(self,other):
+        return update_chain(self,other)
+                
+    
+    def update_mem_pool(self,other):
+        if other._delayed_tx:
+            fill_mem_pool(other)
+        return update_pool(self,other.mem_pool)
+
+
+    def update_utxo_set(self,other):
+        self.utxo_set.update(other.utxo_set)
+              
+    ############################################################
+    # peer as recorder
+    ############################################################
+    
+    """
+    if u r a consensus peer, u have create a candidate block
+    """
+    
+    def create_candidate_block(self):
+        self.choose_tx_candidates()
+        txs = self.candidate_block_txs
+        value = self.get_block_reward() + self.calculate_fees(txs)
+        coinbase = self.create_coinbase(value)
+        txs = [coinbase]+txs
+        
+        prev_block_hash = self.blockchain[-1].hash
+        bits = Params.INITIAL_DIFFICULTY_BITS 
+        self.candidate_block = Block(version=0, 
+                                     prev_block_hash=prev_block_hash,
+                                     timestamp = self.network.time[-1],
+                                     bits = bits, 
+                                     nonce = 0,
+                                     txs = txs or [])
+        
+        self._is_block_candidate_created = True
+        
+    
+    '''
+    pow used right now
+    '''        
+    def consensus(self,meth = 'pow'):
+        if not self._is_block_candidate_created:
+            self.create_candidate_block()
+            self._is_block_candidate_created = False
+            
+        if meth == 'pow':
+            return mine(self.candidate_block)
+
+    """
+    if this is a recorder peer, we have package the candidate block
+    """
+    def package_block(self,nonce):
+        block = self.candidate_block._replace(nonce = nonce)
+        return block
+
+    """
+    choose transactions for candidate block 
+    """
+    def choose_tx_candidates(self):
+        if self.tx_choice_method == 'whole':
+            if not self.mem_pool:
+                self.update_mem_pool(self.network.peers[0])
+            self.candidate_block_txs = choose_whole_txs_from_pool(self.mem_pool)
+        
+        elif self.tx_choice_method == 'random':
+            if not self.mem_pool:
+                self.update_mem_pool(self.network.peers[0])
+            self.candidate_block_txs = choose_raondom_txs_from_pool(self.mem_pool)
+
+    """
+    get transactions for candidate block
+    """
+    def get_tx_candidates(self):  
+        return self.candidate_block_txs
+    
+    def get_height(self):
+        return len(self.blockchain)
+    
+    def roll_back_now(self):
+        roll_back(self)
+
+    def __repr__(self):
+        return 'peer{0}'.format(self.coords)
+    
+    
+# =============================================================================
+#login and logout
+
+def repeat_log_in(peer,net):
+    net.off_peers.remove(peer)
+    net.peers.append(peer)
+    
+def log_out(peer,net):
+    net.peers.remove(peer)
+    net.off_peers.append(peer)
+    peer.mem_pool = []
+
+def update_chain(peer,other):
+    other_height = other.get_height()
+    height = peer.get_height()
+    if other_height > height:
+        peer.blockchain = []
+        for block in other.blockchain:
+            peer.blockchain.append(block)
+        return True
+    return False
+    
+
+def update_pool(peer,pool):
+    a,b = set(peer.mem_pool),set(pool)
+    for tx_id in (b-a):
+        tx = pool.get(tx_id)
+        peer.mem_pool[tx_id] = tx
+    
+    if peer._delayed_tx:
+        fill_mem_pool(peer)
+    
+    if peer.orphan_pool:
+        check_orphan_tx_from_pool(peer)
+        
+    return True
+
+    
+
+# =============================================================================         
+#create transactions
+def create_normal_tx(peer,to_addr,value) :
+    utxos,balance = peer.get_utxo(),peer.get_balance()
+    fee,wallet = peer.fee,peer.wallet
+    
+    tx_in,tx_out = [],[]
+    value = value + fee
+    if balance  < value:
+        logger.info('no enough money for transaction for {0}(pid = {1})'.format(peer,peer.pid))
+        return
+        
+    need_to_spend,n = 0,0
+    for i,utxo in enumerate(utxos):
+        need_to_spend += utxo.vout.value
+        if need_to_spend >= value:
+            n = i+1
+            break
+            
+    if need_to_spend > value:
+        my_addr = wallet.addrs[-1]
+        tx_out +=[Vout(to_addr,value-fee),Vout(my_addr,need_to_spend-value)]
+    else:
+        tx_out += [Vout(to_addr,value-fee)]
+            
+            
+    for utxo in utxos[:n]:
+        addr = utxo.vout.to_addr
+        idx = wallet.addrs.index(addr)
+        sk,pk = wallet.keys[idx].sk,wallet.keys[idx].pk
+        
+        string = str(utxo.pointer) + str(pk.to_bytes()) + str(tx_out)
+        message = build_message(string)
+        signature = sk.sign(message)
+        tx_in.append(Vin(utxo.pointer,signature,pk.to_bytes()))
+        
+    return tx_in,tx_out,fee
+
+
+def create_subtle_tx(nd,to_addr,value):
+    pass
+
+def choose_raondom_txs_from_pool(pool):
+    n = len(pool)
+    n = n if n < Params.MAX_TX_NUMBER_FOR_MINER else Params.MAX_TX_NUMBER_FOR_MINER
+    candidates = random.sample(list(pool.keys()),n)
+    return [pool.get(t) for t in candidates]
+
+def choose_whole_txs_from_pool(pool):
+    return list(pool.values())
+
+# =============================================================================
+#broadcast transactions  
+# =============================================================================
+    
+def broadcast_tx(peers,current_tx):    
+    rand,idxs,choice = random.uniform(0,1),range(len(peers)),[-1]
+    number_of_verification = 0
+    
+    if rand < Params.SLOW_PEERS_IN_NETWORK:
+        choice = [random.choice(idxs)]
+    if rand < Params.SLOWER_PEERS_IN_NETWORK:
+        choice = random.sample(idxs,k = 2)
+
+    for i,peer in enumerate(peers): 
+        if peer._delayed_tx:
+            dice = random.uniform(0,1)
+            if dice > Params.SLOW_PEERS_IN_NETWORK:
+                fill_mem_pool(peer)
+            
+        if peer.verify_transaction(current_tx,peer.mem_pool):
+            if (i in choice) and (not peer._delayed_tx):
+                peer._delayed_tx = current_tx
+                continue
+            
+            add_tx_to_mem_pool(peer,current_tx)  
+            number_of_verification += 1 
+            
+        if peer.orphan_pool:
+            check_orphan_tx_from_pool(peer)
+            
+    return number_of_verification
+
+
+def check_orphan_tx_from_pool(peer):
+    copy_pool = peer.orphan_pool.copy()
+    for tx in copy_pool.values():
+        if not verify_tx(tx,peer.mem_pool):
+            return False
+        add_tx_to_mem_pool(peer,tx)
+        del peer.orphan_pool[tx.id]
+    return True
+            
+# =============================================================================
+#broadcast_block
+# =============================================================================
+    
+def broadcast_winner_block(peers,block): 
+    number_of_verification = 0
+    for peer in peers: 
+        if peer.verify_block(block):
+            try_to_add_block(peer,block)
+            number_of_verification += 1
+    
+    return number_of_verification
+    
+        
+# =============================================================================
+#UTXO functions
+# =============================================================================
+
+def find_utxos_from_txs(txs):
+    return [UTXO(vout,Pointer(tx.id,i),tx.is_coinbase)
+            for tx in txs for i,vout in enumerate(tx.tx_out)]
+    
+def find_utxos_from_block(txs):
+    return [UTXO(vout,Pointer(tx.id,i),tx.is_coinbase,True,True)
+            for tx in txs for i,vout in enumerate(tx.tx_out)]
+    
+def find_utxos_from_tx(tx):
+    return [UTXO(vout,Pointer(tx.id,i),tx.is_coinbase)
+            for i,vout in enumerate(tx.tx_out)]
+
+def find_vout_pointer_from_txs(txs):
+    return [Pointer(tx.id,i) for tx in txs for i,vout in enumerate(tx.tx_out)]
+    
+def find_vin_pointer_from_txs(txs):
+    return [vin.to_spend for tx in txs for vin in tx.tx_in]
+            
+##def confirm_utxos_from_txs(utxo_set,txs,allow_utxo_from_pool):
+##    if allow_utxo_from_pool:
+##        utxos = find_utxos_from_txs(txs[1:])
+##        add_utxos_from_tx_to_set(utxo_set,txs[0])
+##        pointers = find_vout_pointer_from_txs(txs)
+##        confirm_utxo_by_pointers(utxo_set,pointers)
+##        return pointers,utxos
+##    else:
+##        utxos = find_utxos_from_block(txs)
+##        pointers = find_vout_pointer_from_txs(txs)
+##        add_utxos_to_set(utxo_set,utxos)
+##        return pointers,utxos
+
+def confirm_utxos_from_txs(utxo_set,txs,allow_utxo_from_pool):
+    if allow_utxo_from_pool:
+        utxos = find_utxos_from_txs(txs[1:])
+        add_utxo_from_block_to_set(utxo_set,txs)
+        pointers = find_vout_pointer_from_txs(txs)
+        return pointers,utxos
+    else:
+        utxos = find_utxos_from_block(txs)
+        pointers = find_vout_pointer_from_txs(txs)
+        add_utxos_to_set(utxo_set,utxos)
+        return pointers,[]
+    
+def remove_spent_utxo_from_txs(utxo_set,txs):
+    pointers = find_vin_pointer_from_txs(txs)
+    utxos = delete_utxo_by_pointers(utxo_set,pointers)
+    return utxos
+
+def delete_utxo_by_pointers(utxo_set,pointers):
+    utxos_from_vins = []
+    for pointer in pointers:
+        if pointer in utxo_set:
+            utxos_from_vins.append(utxo_set[pointer])
+            del utxo_set[pointer]
+    return utxos_from_vins
+
+
+            
+def sign_utxo_from_tx(utxo_set,tx):
+    for vin in tx.tx_in:
+        pointer = vin.to_spend
+        utxo = utxo_set[pointer]
+        utxo = utxo._replace(unspent = False)
+        utxo_set[pointer] = utxo
+
+                    
+def add_utxos_from_tx_to_set(utxo_set,tx):
+    utxos = find_utxos_from_tx(tx)
+    for utxo in utxos:
+        utxo_set[utxo.pointer] = utxo
+        
+        
+def add_utxo_from_txs_to_set(utxo_set,txs):
+    utxos = find_utxos_from_txs(txs)
+    add_utxos_to_set(utxo_set,utxos)
+
+def add_utxo_from_block_to_set(utxo_set,txs):
+    utxos = find_utxos_from_block(txs)
+    add_utxos_to_set(utxo_set,utxos)
+    
+def add_utxos_to_set(utxo_set,utxos):
+    if isinstance(utxos,dict):
+        utxos = utxos.values()
+        
+    for utxo in utxos:
+        utxo_set[utxo.pointer] = utxo
+
+def remove_utxos_from_set(utxo_set,pointers):
+    for pointer in pointers:
+        if pointer in utxo_set:
+            del utxo_set[pointer]
+    
+# =============================================================================
+#verify transaction
+# =============================================================================
+        
+def verify_tx(peer,tx,pool = {}):
+    
+    if not verify_tx_basics(tx):
+        return False
+
+    if double_payment(pool,tx):
+        logger.info('{0} double payment'.format(tx))
+        return False
+    
+    available_value = 0
+
+    for vin in tx.tx_in:
+        utxo = peer.utxo_set.get(vin.to_spend)
+        
+        if not utxo:
+            logger.info(
+                    '{0}(pid={1}) find a orphan transaction {2}'.format(peer,peer.pid,tx)
+                    )
+            peer.orphan_pool[tx.id] = tx
+            return False
+
+        if not verify_signature(peer,vin,utxo,tx.tx_out):
+            logger.info('singature does not math for {0}'.format(tx))
+            return False
+    
+        available_value += utxo.vout.value
+        
+    if available_value < sum(vout.value for vout in tx.tx_out):
+        logger.info(
+                '{0} no enought available value to spend by {1}(pid={2})'.format(tx,peer,peer.pid)
+                )
+        return False
+
+    return True
+
+def verify_signature(peer,vin,utxo,tx_out):
+    script = check_script_for_vin(vin,utxo,peer.key_base_len)
+    if not script:
+        return False
+    string = str(vin.to_spend) + str(vin.pubkey) + str(tx_out)
+    message = build_message(string)
+    peer.machine.set_script(script,message)
+    return peer.machine.run()
+
+
+def check_script_for_vin(vin,utxo,baselen):
+    sig_script,pubkey_script = vin.sig_script,utxo.pubkey_script
+    double,fourfold = int(baselen*2),int(baselen*4)
+    if len(sig_script) != fourfold:
+        return False
+    sig_scrip = [sig_script[:double],sig_script[double:]]
+    try:
+        pubkey_script = pubkey_script.split(' ')
+    except Exception:
+        return False
+
+    return sig_scrip+pubkey_script
+
+
+def verify_signature_for_vin(vin,utxo,tx_out):
+    pk_str,signature = vin.pubkey,vin.signature
+    to_addr = utxo.vout.to_addr
+    string = str(vin.to_spend) + str(pk_str) + str(tx_out)
+    message = build_message(string)
+    pubkey_as_addr = convert_pubkey_to_addr(pk_str)
+    verifying_key = VerifyingKey.from_bytes(pk_str)
+
+    if pubkey_as_addr != to_addr:
+        return Fasle
+    
+    if not verifying_key.verify(signature, message):
+        return Fasle
+
+    return True
+
+    
+def verify_tx_basics(tx):
+    if not isinstance(tx,Tx):
+        logger.info('{0} is not Tx type'.format(tx))
+        return False
+    
+    if (not tx.tx_out) or (not tx.tx_in):
+        logger.info('{0} Missing tx_out or tx_in'.format(tx))
+        return False
+    return True
+
+def double_payment(pool,tx):
+    if tx.id in pool:
+        return True
+    a = {vin.to_spend for vin in tx.tx_in}
+    b = {vin.to_spend for tx in pool.values() for vin in tx.tx_in}
+    return a.intersection(b)
+
+def verify_coinbase(tx,reward):
+    if not isinstance(tx,Tx):
+        return False
+    if not tx.is_coinbase:
+        return False
+    if (not (len(tx.tx_out) ==1))  or (tx.tx_out[0].value != reward):
+        return False
+    return True
+
+# =============================================================================
+#verify block
+# =============================================================================
+    
+def verify_winner_block(peer,block):
+
+    if not isinstance(block,Block):
+        return False
+    
+    if int(block.hash, 16) > caculate_target(block.bits):
+        logger.info('{0} wrong answer'.format(block))
+        return False
+    
+    txs = block.txs
+    if not isinstance(txs,list) and \
+       not isinstance(txs,tuple):
+        logger.info('incorrect txs type in {0}'.format(block))
+        return False
+    
+    if len(txs) < 2:
+        logger.info('no enough txs for txs {0}'.format(block))
+        return False
+
+    block_txs = txs[1:]
+    rewards = peer.get_block_reward()+peer.calculate_fees(block_txs)
+    if not verify_coinbase(block.txs[0],rewards):
+        logger.info('{0} coinbase incorrect'.format(block))
+        return False
+
+    
+    if double_payment_in_block_txs(block_txs):
+        logger.info('double payment in {0}'.format(block))
+        return False
+
+    for tx in block_txs:
+        if not verify_tx(peer,tx):
+            return False
+    return True
+
+def double_payment_in_block_txs(txs):
+    a = {vin.to_spend for tx in txs for vin in tx.tx_in}
+    b = [vin.to_spend for tx in txs for vin in tx.tx_in]
+    return len(a) != len(b)
+    
+    
+# =============================================================================
+#try to recieve a block
+# =============================================================================
+    
+def locate_block_by_hash(peer,block_hash):
+    for height,block in enumerate(peer.blockchain):
+        if block.hash == block_hash:
+            return height+1
+    return None
+        
+def try_to_add_block(peer,block):  
+    prev_hash = block.prev_block_hash                                                  
+    height = locate_block_by_hash(peer,prev_hash)
+    if not height:
+        logger.info('{0}(pid={1} find a orphan {2})'.format(peer,peer.pid,block))
+        peer.orphan_block.append(block)
+        return False
+    
+    if height == peer.get_height():
+        peer.blockchain.append(block)
+        recieve_new_prev_hash_block(peer,block.txs)
+        return True
+    
+    elif height == peer.get_height()-1:
+        b1,b2 = peer.blockchain[-1],block
+        a,b = int(b1.hash,16),int(b2.hash,16)
+        if a < b:
+            return False
+        else:
+            peer.blookchian.pop()
+            peer.blockchain.append(block)
+            recieve_exist_prev_hash_block(peer,block.txs)
+    else:
+        return False
+    
+def check_orphan_block(peer):
+    pass
+
+def recieve_new_prev_hash_block(peer,txs):
+    utxo_set,pool = peer.utxo_set,peer.mem_pool
+    allow_utxo_from_pool = peer.allow_utxo_from_pool
+    peer._utxos_from_vins = remove_spent_utxo_from_txs(utxo_set,txs)
+    peer._pointers_from_vouts,peer._utxos_from_vouts = confirm_utxos_from_txs(
+            utxo_set,txs,allow_utxo_from_pool
+            )
+    peer._txs_removed = remove_txs_from_pool(pool,txs)
+    
+    
+def recieve_exist_prev_hash_block(peer,txs):
+    roll_back(peer)
+    recieve_new_prev_hash_block(peer,txs)
+
+def roll_back(peer):
+    peer.mem_pool.update(peer._txs_removed)
+    add_utxos_to_set(peer.utxo_set,peer._utxos_from_vins)
+    remove_utxos_from_set(peer.utxo_set,peer._pointers_from_vouts)
+    add_utxos_to_set(peer.utxo_set,peer._utxos_from_vouts)
+    peer._utxos_from_vins = []
+    peer._pointers_from_vouts = []
+    peer._utxos_from_vouts = []
+    peer._txs_removed = {}
+    
+def compare_block_by_hash(a,b):
+    pass
+        
+# =============================================================================
+#transactions functions
+# =============================================================================
+    
+def get_unknown_txs_from_block(mem_pool,txs):
+    substraction = {}
+    for tx in txs:
+        if tx not in mem_pool.values():
+            substraction[tx.id] = tx
+    return substraction
+
+
+def fill_mem_pool(peer):
+    add_tx_to_mem_pool(peer,peer._delayed_tx)
+    peer._delayed_tx = None
+        
+
+def remove_txs_from_pool(pool,txs):
+    n_txs = {}
+    for tx in txs:
+        if tx.id in pool:
+            n_txs[tx.id] = tx
+            del pool[tx.id]
+    return n_txs
+                
+def add_txs_to_pool(pool,txs):
+    for tx in txs:
+        pool[tx.id] = tx
+           
+def add_tx_to_mem_pool(peer,tx):
+    peer.mem_pool[tx.id] = tx
+    if peer.allow_utxo_from_pool:
+        add_utxos_from_tx_to_set(peer.utxo_set,tx)
+
+def calculate_next_block_bits(local_time,prev_height,prev_bits):
+    flag = (prev_height + 1) % Params.TOTAL_BLOCKS
+    if flag != 0:
+        return prev_bits
+    
+    count = ((prev_height + 1)//Params.TOTAL_BLOCKS)*Params.TOTAL_BLOCKS
+    actual_time_taken = local_time[:prev_height] - local_time[:count]
+    
+    if actual_time_taken < Params.PERIOD_FOR_TOTAL_BLOCKS:
+        return prev_bits + 1
+    elif actual_time_taken > Params.PERIOD_FOR_TOTAL_BLOCKS:
+        return prev_bits - 1
+    else:
+        return prev_bits
+
+
+          
+if __name__ == '__main__':
+    a,b = Peer(),Peer()