docs: def handle_headers( self, message_header, block_headers_message ):
          """
          Handle a 'headers' message.
          NOTE: we request headers in order, so we will expect to receive them in order here.
          Verify that we do so.
          """
          log.debug("handle headers (%s)" % len(block_headers_message.headers))
  
          block_headers = block_headers_message.headers
  
          serializer = BlockHeaderSerializer()
  
          # verify that the local header chain connects to this sequence
          current_height = SPVClient.height( self.path )
          if current_height is None:
              assert USE_TESTNET
              current_height = -1
  
          assert (current_height >= 0 and USE_MAINNET) or USE_TESTNET, "Invalid height %s" % current_height
      
          last_header = None
  
          if current_height >= 0:
              last_header = SPVClient.read_header( self.path, current_height )
              log.debug("Receive %s headers (%s to %s)" % (len(block_headers), current_height, current_height + len(block_headers)))
  
          else:
              # first testnet header
              log.debug("Receive %s testnet headers (%s to %s)" % (len(block_headers), current_height + 1, current_height + len(block_headers)))
              last_header = {
                  "version": block_headers[0].version,
                  "prev_block_hash": "%064x" % block_headers[0].prev_block,
                  "merkle_root": "%064x" % block_headers[0].merkle_root,
                  "timestamp": block_headers[0].timestamp,
                  "bits": block_headers[0].bits,
                  "nonce": block_headers[0].nonce,
                  "hash": block_headers[0].calculate_hash()
              }
  
          if (USE_MAINNET or (USE_TESTNET and current_height >= 0)) and last_header['hash'] != self.hash_to_string(block_headers[0].prev_block):
              raise Exception("Received discontinuous block header at height %s: hash '%s' (expected '%s')" % \
                      (current_height,
                      self.hash_to_string(block_headers[0].prev_block),
                      last_header['hash'] ))
  
          header_start = 1
          if USE_TESTNET and current_height < 0:
              # save initial header
              header_start = 0
  
          # verify that this sequence of headers constitutes a hash chain 
          for i in xrange(header_start, len(block_headers)):
              prev_block_hash = self.hash_to_string(block_headers[i].prev_block)
              if i > 0 and prev_block_hash != block_headers[i-1].calculate_hash():
                  raise Exception("Block '%s' is not continuous with block '%s'" % \
                          prev_block_hash,
                          block_headers[i-1].calculate_hash())
  
          if current_height < 0:
              # save the first header 
              if not os.path.exists(self.path):
                  with open(self.path, "wb") as f:
                      block_header_serializer = BlockHeaderSerializer()
                      bin_data = block_header_serializer.serialize( block_headers[0] )
                      f.write( bin_data )
  
              # got all headers, including the first
              current_height = 0
  
          # insert into to local headers database
          next_block_id = current_height + 1
          for block_header in block_headers:
              with open(self.path, "rb+") as f:
  
                  # omit tx count 
                  block_header.txns_count = 0
                  bin_data = serializer.serialize( block_header )
  
                  if len(bin_data) != BLOCK_HEADER_SIZE:
                      raise Exception("Block %s (%s) has %s-byte header" % (next_block_id, block_header.calculate_hash(), len(bin_data)))
  
                  # NOTE: the fact that we use seek + write ensures that we can:
                  # * restart synchronizing at any point
                  # * allow multiple processes to work on the chain safely (even if they're duplicating effort)
                  f.seek( BLOCK_HEADER_SIZE * next_block_id, os.SEEK_SET )
                  f.write( bin_data )
  
                  if SPVClient.height( self.path ) >= self.last_block_id - 1:
                      break
  
                  next_block_id += 1
              
          current_block_id = SPVClient.height( self.path )
          if current_block_id >= self.last_block_id - 1:
              # got all headers
              self.loop_exit()
              return
  
          prev_block_header = SPVClient.read_header( self.path, current_block_id )
          prev_block_hash = prev_block_header['hash']
          self.send_getheaders( prev_block_hash )