def handle_block( self, message_header, block ):
        """
        Got a block.
        * validate it
        * load its transactions
        * ask for each transaction's sender transaction
        """

        if self.have_all_block_data():
            self.loop_exit()
            return

        block_hash = block.calculate_hash()
        
        # is this a solicited block?
        if block_hash not in self.block_info.keys():
            log.error("Ignoring unsolicited block %s" % block_hash)
            return
        
        header = self.block_info[block_hash]['header']
        height = self.block_info[block_hash]['height']
        
        log.debug("handle block %s (%s)" % (height, block_hash))

        # does this block's transaction hashes match the merkle root?
        tx_hashes = [block.txns[i].calculate_hash() for i in range(0, len(block.txns))]
        block_merkle_tree = merkle.MerkleTree(tx_hashes)
        mr = block_merkle_tree.root()

        if mr != header['merkle_root']:
            log.error("Merkle root of %s (%s) mismatch: expected %s, got %s" % (block_hash, height, header['merkle_root'], mr))
            return

        merkle_paths = {}       # map txid to merkle path

        # make sure we have merkle paths for each tx
        for i in range(0, len(block.txns)):
            txid = block.txns[i].calculate_hash()
            merkle_path = block_merkle_tree.path(txid)
            if merkle_path is None:
                log.error("No merkle path for {}".format(txid))
                return 

            merkle_paths[txid] = merkle_path
 
        nulldata_txs = []
        relindex = 0
        for txindex in range(0, len(block.txns)):

            txdata = self.parse_tx( block.txns[txindex], header, block_hash, txindex )

            # if there is no nulldata output, then we don't care about this one.
            has_nulldata = False
            nulldata_payload = None

            for outp in txdata['outs']:
                script_type = bits.btc_script_classify(outp['script'])
                if script_type == 'nulldata':
                    # to be clear, we only care about outputs that take the form
                    # OP_RETURN <string length> <string data>
                    nulldata_script = bits.btc_script_deserialize(outp['script'])
                    if len(nulldata_script) < 2:
                        # malformed OP_RETURN; no data after '6a'
                        nulldata_payload = None
                        has_nulldata = False

                    elif len(nulldata_script) == 2 and isinstance(nulldata_script[1], (str,unicode)):
                        # well-formed OP_RETURN output
                        nulldata_payload = nulldata_script[1]
                        has_nulldata = True
                   
                    else:
                        # this is something like OP_RETURN OP_2 (e.g. "6a52")
                        # there's nothing for us here.
                        nulldata_payload = None
                        has_nulldata = False

            # count all txs processed
            self.num_txs_processed += 1

            if not has_nulldata:
                continue

            # remember nulldata, even if it's empty
            txdata['nulldata'] = nulldata_payload 

            # remember merkle path
            txdata['tx_merkle_path'] = merkle_paths[txdata['txid']]
            
            # calculate total output (part of fee; will be debited when we discover the senders)
            # NOTE: this works because we have out['value'] as type Decimal
            # txdata['fee'] -= sum( int(out['value'] * 10**8) for out in txdata['vout'] )
            txdata['fee'] -= sum(out['value'] for out in txdata['outs'])

            # remember the relative tx index (i.e. the ith nulldata tx)
            txdata['relindex'] = relindex
            
	    # do we actually want this?
            if self.tx_filter is not None:
                if not self.tx_filter( txdata ):
                    continue

            # yup, we want it!
            relindex += 1
            nulldata_txs.append( txdata )


        self.block_info[block_hash]['txns'] = nulldata_txs
        self.block_info[block_hash]['num_txns'] = len(block.txns)
        self.block_info[block_hash]['num_senders'] = 0

        # get each input's transaction
        sender_txhashes = []

        for txn in self.block_info[block_hash]['txns']:
            for i in range(0, len(txn['ins'])):

                # record information about the transaction
                # that created this input (so we can go find
                # it later).
                inp = txn['ins'][i]
                sender_txid = inp['outpoint']['hash']
                inp_sender_outp = inp['outpoint']['index']

                if str(sender_txid) not in sender_txhashes:
                    sender_txhashes.append( str(sender_txid) )

                sinfo = self.make_sender_info( block_hash, txn, i, height )

                if not self.sender_info.has_key(sender_txid):
                    # map outpoint for this input to the tx info
                    self.sender_info[sender_txid] = {}

                # sinfo is the information from the output in 
                # the sender-tx that funded inp
                self.sender_info[sender_txid][inp_sender_outp] = sinfo

        # update accounting...
        self.num_blocks_received += 1
        self.block_info[block_hash]['handled'] = True

        log.debug("Request %s nulldata sender TXs" % len(sender_txhashes))

        if self.have_all_block_data():
            self.loop_exit()

        return
Got a block.
        * validate it
        * load its transactions
        * ask for each transaction's sender transaction