docs: 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